1

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

是模棱两可的,所以f()对象底部没有唯一的方法。现在,打电话

b->g()

工作正常并打印

Base.f

好吧,据我所知:

  1. 静态类型是Bottom,所以我们称之为它的g()方法,因为它是非虚拟的
  2. g()方法是继承自Left,所以我们称这个继承方法
  3. 现在,g()在 Left 尝试调用虚拟方法f()。根据 C++ 规范,我们调用f()指针的动态类型的方法(即底部)

但是底部没有方法f()……至少不是一个独特的方法。为什么这个程序执行Left::Base::f()而不是Right::Base::f()或者为什么它根本没有说明对f()底部的调用是模棱两可的?

4

2 回答 2

2

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

Bottom包含两个子对象LeftRight. 它们中的每一个都继承自Base,因此Bottom包含成员函数Left::f()and Right::f(),但没有Bottom::f()。由于底部不覆盖Left::f()Right::f()例如使用),Base::f()Left::g().

参看。来自 C++03 标准的 10.3.9 中的示例。

于 2012-04-15T21:40:23.363 回答
1

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

f直接调用Bottom是模棱两可的,因为其中没有将尝试查看它的基础并会找到f()并且编译器不知道要使用两者中的哪一个。BottomLeft::Base::fRight::Base::f

于 2012-04-15T21:54:54.000 回答