虚拟继承和非虚拟继承的混合 在试图更深入地分析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(); }

虚拟继承和非虚拟继承的混合 在试图更深入地分析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(); },c++,inheritance,multiple-inheritance,virtual-functions,C++,Inheritance,Multiple Inheritance,Virtual Functions,不明确,因此在对象底部没有唯一的方法f()。现在,打电话 b->g() 作品精美,印刷精美 Base.f 那么就我看, 静态类型是Bottom,所以我们调用它的g()方法,因为它是非虚拟的 g()方法是从左侧继承的,所以我们称之为继承的方法 现在,左边的g()尝试调用虚拟方法f()。根据C++的SISCISCUTIZE,我们调用了一个动态类型的指针(即底部) f>(/>代码>方法> 但底部没有方法f()。。。至少不是唯一的。为什么这个程序执行Left::Base::f()而不是Rig

不明确,因此在对象底部没有唯一的方法
f()
。现在,打电话

b->g()
作品精美,印刷精美

Base.f
那么就我看,

  • 静态类型是Bottom,所以我们调用它的
    g()
    方法,因为它是非虚拟的
  • g()
    方法是从左侧继承的,所以我们称之为继承的方法
  • 现在,左边的
    g()
    尝试调用虚拟方法
    f()
    。根据C++的SISCISCUTIZE,我们调用了一个动态类型的指针(即底部)
  • <代码> f>(/>代码>方法> 但底部没有方法
    f()
    。。。至少不是唯一的。为什么这个程序执行
    Left::Base::f()
    而不是
    Right::Base::f()
    ,或者为什么它只是不声明对
    f()
    的调用从底部看是不明确的?

    简短的回答是(正如您所指出的),
    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中的示例。

    由于没有虚拟继承,因此
    底部的
    对象中有两个
    Base
    对象的副本。但是如果将层次结构向上移动到定义了
    g()
    Left
    ,则存在一个
    Base
    子对象,该子对象就是被调用的子对象。由于它在
    Left
    (或
    Bottom
    )中未被覆盖,因此它将调用
    Base
    版本。请注意,
    Right::f()
    仅覆盖它自己的
    Base
    子对象的
    f()


    直接在
    Bottom
    上调用
    f
    是不明确的,因为
    Bottom
    中没有
    f()
    ,它将尝试查找它的基,并将找到
    Left::Base::f
    Right::Base::f
    ,编译器不知道使用这两个中的哪一个。

    这完全不是我要求的。。。C++的规范称调用动态类型的方法,但是这里,动态类型根本没有f-()。那么我们为什么要调用任何东西呢?@Bober02:dynamic类型实际上在层次结构的每一侧都有两个
    f()
    一个。请注意,标准所说的是将调用函数的最终重写器,这是关键点。虽然有两个
    f
    ,但是当您将函数声明为虚拟函数时,
    Left::Base::f
    有一个重写器,它将始终是虚拟的,这与当前的问题有什么关系?我知道我们需要调用dynamic type的方法。除此之外,方法也可以隐藏,您可以通过简单地用相同的签名重写虚拟方法来隐藏虚拟方法,但将其设置为非虚拟方法。谢谢您的回答和评论。最终重写器。。。该死,这太复杂了。关于多重虚拟/非虚拟继承,有什么好的来源可以解释这样的边缘情况吗?我找不到写得好的…@Bober02没那么复杂。只要想想存在的对象:因为继承不是虚拟的,所以您有两个子对象。一旦您能够识别对象,就很容易遵循覆盖链,唯一奇怪的行为是单个方法可以覆盖多个虚拟函数(每个基最多一个),您认为一个方法可以覆盖多个虚拟函数是什么意思?你能举个例子吗?顺便说一句,在你看来,关于这类高级主题的最佳资源是什么?Thanks@Bober02:最好的资源是经验,到处都能阅读。例如:
    struct A{virtual void f(){};结构B{virtualvoid f(){}};结构C:A,B{virtualvoidf(){}
    C::f
    A::f
    B::f
    的最终重写器。签名必须匹配,但单个函数可以覆盖多个虚拟函数(如示例所示)到处读取。。。这是一个漂亮的大声明。有关于高级主题的好书吗?顺便说一句,你介意看看我刚才贴的这个问题吗?谢谢:
    Base.f