虚函数和默认参数

Virtual functions and default parameters

假设我有 class A、B 和 C

class A{
    public:
        virtual void f4(){
            cerr<<"A::f4()"<<endl;
        }
};


class B: public A{
    public: 
        virtual void f4(int n){
            cerr<<"B::f4("<<n<<")"<<endl;
        }
};

class C: public B{
    public:
        virtual void f4(int n = 1){
            cerr<<"C::f4("<<n<<")"<<endl;
        }
};

如果我有:

C c;
A& rac = c;
rac.f4();

我原以为会调用 c 的 f4 版本,但事实并非如此。有人可以解释吗?

因为 f4 的签名在 A 和 B/C classes 之间不匹配。

这是 A 对 f4 的函数签名:

void A::f4()  // no parameters

B和C使用这个函数签名

void B::f4(int n)

如果您要覆盖一个方法,它需要具有相同的 return 类型和相同的参数列表。否则,即使派生 class 中的方法与父 class 中的方法同名,C++ 也不会将其视为覆盖。

FWIW,C::f4 确实覆盖了 B::f4。您在 class C 上引入的默认参数不会影响虚拟方法覆盖行为。这就是为什么在我的团队中,我们不允许重载具有不同签名的方法并禁止默认参数的确切原因。因为它会导致这样的错误。

这里是C的v-table(上面可用的方法):

void C::f4(); // no parameters, overrides A::f4()
void C::f4(int n);  // overrides B::f4()

编译with clang -Wall出现以下警告:

main.cpp:14:22: warning: 'B::f4' hides overloaded virtual function [-Woverloaded-virtual]
    virtual void f4(int n){
                 ^
main.cpp:6:22: note: hidden overloaded virtual function 'A::f4' declared here: different number of parameters (0 vs 1)
    virtual void f4(){
                 ^

这些警告解释了发生了什么。虚函数只能被具有相同签名的另一个函数覆盖。

B::f4(int) 不会覆盖 A::f4() 因为它们有不同的参数列表。相反,它是一个不同的虚函数。

所以 rac.f4() 只是调用 A::f4(),它没有被覆盖。

从 C++11 开始,您可以帮助检测这个问题:

virtual void f4(int n) override {
//                     ^^^^^^^^

如果这个函数实际上没有覆盖基类的东西,编译器会报错。