虚拟和非虚拟继承的混合

时间:2012-04-15 21:34:19

标签: c++ inheritance multiple-inheritance virtual-method

在尝试更深入地分析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

嗯,据我所知:

  1. 静态类型是底部,所以我们称之为g()方法,因为它是非虚拟的
  2. g()方法是从Left继承的,所以我们称之为继承方法
  3. 现在,左侧的g()尝试调用虚方法f()。根据C ++ sepcification,我们调用f()方法的动态类型的指针(这是底部)
  4. 但是底部没有方法f() ......至少不是唯一的方法。为什么这个程序执行Left::Base::f()而不是Right::Base::f(),或者为什么它只是没有说明对f()的调用是不明确的?

2 个答案:

答案 0 :(得分:2)

简短的回答是(正如您所说),Bottom没有方法f(),因此无需尝试调用它。

Bottom包含两个子对象LeftRight。它们中的每一个都继承自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::fRight::Base::f并且编译器不知道要使用哪两个。