假设我有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();
我期待被调用的f4版本的f4,但事实并非如此。谁能解释一下?
答案 0 :(得分:2)
因为f4的签名在A和B / C类之间不匹配。
这是f4的A函数签名:
void A::f4() // no parameters
B和C使用此功能签名
void B::f4(int n)
如果要覆盖方法,则需要具有相同的返回类型和相同的参数列表。否则,即使派生类中的方法与父类具有相同的名称,C ++也不会认为是覆盖。
FWIW,C::f4
覆盖B::f4
。您在class C
上引入的默认参数不会影响虚拟方法覆盖行为。这就是为什么我的团队不允许使用不同签名重载方法并禁止默认参数的原因。因为它会导致像这样的错误。
这是C&#39的v-table(可用的方法):
void C::f4(); // no parameters, overrides A::f4()
void C::f4(int n); // overrides B::f4()
答案 1 :(得分:2)
编译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 {
// ^^^^^^^^
如果此函数实际上没有覆盖基类中的某些内容,则编译器将给出错误。