在尝试更深入地分析C ++的继承机制时,我偶然发现了以下示例:
#include<iostream>
using namespace std;
class Base {
public:
virtual void f(){
cout << "Base.f" << endl;
}
};
class Left : public Base { //NOT VIRTUAL!!!
public:
void g(){
f();
}
};
class Right : public Base{
public:
virtual void f(){
cout << "Right.f" << endl;
}
};
class Bottom : public Left, public Right{
public:
Bottom(int arg){ }
//void f() { }
};
int main(int argc,char **argv)
{
Bottom* b = new Bottom(23);
b->g();
}
很明显,调用
b->f()
是不明确的,因此对象Bottom上没有唯一的方法f()
。现在,拨打
b->g()
工作正常并打印
Base.f
嗯,据我所知:
g()
方法,因为它是非虚拟的g()
方法是从Left继承的,所以我们称之为继承方法g()
尝试调用虚方法f()
。根据C ++ sepcification,我们调用f()
方法的动态类型的指针(这是底部)但是底部没有方法f()
......至少不是唯一的方法。为什么这个程序执行Left::Base::f()
而不是Right::Base::f()
,或者为什么它只是没有说明对f()
的调用是不明确的?
答案 0 :(得分:2)
简短的回答是(正如您所说),Bottom
没有方法f()
,因此无需尝试调用它。
Bottom
包含两个子对象Left
和Right
。它们中的每一个都继承自Base
,因此Bottom
包含成员函数Left::f()
和Right::f()
,但不包含Bottom::f()
。由于Bottom不会覆盖Left::f()
(例如,使用Right::f()
),Base::f()
是Left::g()
中唯一的最终覆盖。
比照来自C ++ 03标准的10.3.9中的示例。
答案 1 :(得分:1)
由于没有虚拟继承,因此Base
对象中有Bottom
个对象的两个副本。但是,如果将层次结构向上移动到Left
,其中g()
已定义,则只有一个Base
子对象,即被调用的子对象。由于它未在Left
(或Bottom
)中覆盖,因此会调用Base
版本。请注意,Right::f()
仅为其自己的f()
子对象覆盖Base
。
直接在f
上致电Bottom
是不明确的,因为f()
中没有Bottom
它会尝试查看它的基础并找到Left::Base::f
和Right::Base::f
并且编译器不知道要使用哪两个。