如果派生类重写方法,为什么要调用基类方法?

dan*_*man 6 c++ inheritance

考虑以下计划:

class Base {
public:
    virtual void foo() const {
        cout << "Base::foo()" << endl;
    }
};

class Derived : public Base {
public:
    virtual void foo() {
        cout << "Derived::foo()" << endl;
    }
};

void func(Base& obj) {
    obj.foo();
}

void main() {
    Derived d;
    func(d); // Base::foo() is printed 
}
Run Code Online (Sandbox Code Playgroud)

如果我constBasefoo方法中删除然后Derived::foo()调用.我似乎无法理解这种行为.

1)这种行为的原因是什么?

2)这是在编译时还是在运行时决定的?

谢谢

Naw*_*waz 7

在派生类中,函数签名是这样的:

virtual void foo(); //Derived::foo
Run Code Online (Sandbox Code Playgroud)

哪个没提const.它是一个非const成员函数,而它Base::foo是一个const成员函数.它们是两个不同的函数,因为它const是函数签名的一部分.

virtual void foo() const; //Base::foo 
Run Code Online (Sandbox Code Playgroud)

派生类不会覆盖此函数,而是添加另一个函数.

所以修复是这样的:

class Derived : public Base {
public:
    virtual void foo() const {
        cout << "Derived::foo()" << endl;
    }
};
Run Code Online (Sandbox Code Playgroud)

作为const功能签名的一部分.因此,当你打算覆盖base的foo时,你必须提到它.


@ davka的问道:

为什么选择const版本而非const?是否有任何规则或者恰好是第一个选择?

它因为静态类型objBase,而函数名是根据对象的静态类型来解析的.Base甚至没有非const版本.所以毫无疑问它被选中或被拒绝.它始终不存在Base.

void func(Base& obj) {
    obj.foo();  //calls Base::foo
}
Run Code Online (Sandbox Code Playgroud)

但是,如果您将上面的代码更改为以下代码:

void func(Derived & obj) {
    obj.foo();  //calls Derived:foo
}
Run Code Online (Sandbox Code Playgroud)

现在将选择非const版本,因为Base::foo它隐藏在Derived类中.


由于Derived::foo隐藏了Base::foo,所以你不能使用实例来调用后者Derived.

现在,让我们取消隐藏Base::foo并进行更多实验.

class Derived : public Base {
public:
    using Base::foo;         //<----------------this unhides Base::foo
    virtual void foo() {
        cout << "Derived::foo()" << endl;
    }
};
Run Code Online (Sandbox Code Playgroud)

现在在Derived中,两个函数(const和非const版本)都可用,取消隐藏.现在几个有趣的问题.

从现在开始Derived有两个函数unhidden,下面的每个函数都会调用哪个函数?

void f(Derived& obj) {
    obj.foo(); //Which function? Base::foo or Derived::foo?
}
void g(const Derived & obj) {
    obj.foo(); //Which function? Base::foo or Derived::foo?
}
Run Code Online (Sandbox Code Playgroud)

第一个将调用Derived::foo哪个是非const版本,第二个将调用Base::foo哪个是const版本.原因很简单,使用const对象,只能 调用const函数,但是对于非const对象,都可以调用它们,但是如果可用,则选择非const版本.

请参阅在线演示:http://www.ideone.com/955aY