C ++:继承和重载解析

时间:2012-02-03 05:47:24

标签: c++ inheritance dynamic static overload-resolution

我正在阅读一个C ++难题:http://gotw.ca/gotw/005.htm

我不理解他对静态与动态重载决策(或默认参数)的解释,所以我试着提炼出问题并自己写一些测试:

class Base {
    public:
    virtual void foo() {cout << "base/no parameters" << endl;}
    virtual void foo(int a) {cout << "base/int" << endl;}
};

class Derived : public Base {
    public:
    void foo() {cout << "derived/no parameters" << endl;}
    void foo(double a) {cout << "derived/int" << endl;}
};

int main() {
    Base* ptr = new Derived;
    ptr->foo();
    ptr->foo(1.0);
}

输出结果为:

derived/no parameters
base/int

为了调用foo(),C ++似乎认识到它指向Derived,但在调用foo(1.0)中,C ++没有看到void foo(double a)函数在Derived班?

在我看来,有一些竞争的想法,即C ++具有多态性,这解释了第一次调用,但是重载解析是在编译时完成的,这解释了第二次调用。

6 个答案:

答案 0 :(得分:3)

这是 Function Hiding 的经典示例 当且仅当:

时,dervied类中的函数才会覆盖基类函数
  1. virtual关键字至少存在于基类功能上。
  2. Derived类中的函数与Base类函数具有完全相同的签名。
  3. 第二条规则有一个例外,允许 Covariant return types

    鉴于以上两条规则:

    派生类中的无参数foo()函数覆盖基类foo(),因此动态调度可以按预期工作。

    带有一个参数的foo(double)版本不会覆盖基类foo(int)功能,它只是隐藏它。由于没有覆盖,因此没有动态分派,编译器只调用它在Base类范围内找到的foo(int)函数。

答案 1 :(得分:2)

  

C ++在Derived类中没有看到void foo(double a)函数?

C ++确实看到了这个函数,但是由于函数签名的差异,Base::foo的{​​{1}}没有关联

virtual

所以这里有virtual void Base::foo(int); // 'Base' signature void Derived::foo(double); // 'Derived' signature 的两个重要事实:

  1. Derived::foo(double)
  2. 无关(覆盖)
  3. 不是Base::foo(int)方法(即使使virtual无效)
  4. 第一点更重要,因为当你打电话时

    virtual
    使用

    // 'ptr' refers 'Base' method signature; so 'double' implicitly converts to 'int' ptr->foo(1.0); 指针。在vtable列表中,它只有一个Base条目。因此它被称为。

答案 2 :(得分:2)

ptr的类型为Base*

Base1.0作为参数的唯一功能是virtual void foo(int a)

现在,请记住,对于要虚拟覆盖的函数,它需要完全匹配签名(减去差异,但不适用于您的情况)。您没有覆盖foo(int),但实际上是在创建新的foo(double)

答案 3 :(得分:1)

C ++无法在void foo(double a)类中看到Derived,因为 覆盖void foo(double a)中带有签名Base的虚拟函数class(你试图从中调用它)。

void foo(int a)类中有Base,但根据C ++的规则它是完全不同的函数。


另一方面,void foo()类中的Derived覆盖void foo()类中的虚函数Base,因为它们都具有相同的签名。 / p>

答案 4 :(得分:1)

class Base {
    public:
    virtual void foo() {cout << "base/no parameters" << endl;}
    virtual void foo(int a) {cout << "base/int" << endl;}
        };

class Derived : public Base {
    public:
    void foo() {cout << "derived/no parameters" << endl;}
    void foo(int a) {cout << "derived/int" << endl;}
     //  then your derived class function   will call 
};

int main() {
    Base* ptr = new Derived;
    ptr->foo();
    ptr->foo(1.0);

}

答案 5 :(得分:0)

静态与动态重载分辨率 !!!这是什么意思?

重载始终是静态绑定的,函数将在类中定义(不是一个函数在基类中,而其他函数在派生类中)。

所以foo(double a)和foo(int a)没有重载。同样,这些不会被覆盖,因为签名是不同的。这就是为什么没有为语句ptr-&gt; foo(1.0)发生虚拟机制的原因;