为什么这段代码不起作用? (c ++ OOP)公共继承

时间:2013-01-21 17:39:06

标签: c++ oop inheritance

我想帮助解释这个现象:

#include <iostream>
using namespace std;

class A
{
public:
    void m() {cout<<"A::m "<<this<<endl;};
};

class B1:  public A
{
public:
    void m() {cout<<"B::m "<<this<<endl;};
};

class B2:  public A ,public B1
{
};

class D : public B2
{};

int main()
{
    B2 b;
    D d;
    A* a = &b; // Row 27
    //error: a = &d;  Base class 'A' is ambiguous // Row 28
    return 0;
}

为什么Row27中的代码有效但Row28中的代码不起作用? 提前谢谢!

注意:我很清楚虚拟继承,我只是想知道Row27和Row28之间有什么区别 - 为什么在另一个没有时抛出编译错误?

2 个答案:

答案 0 :(得分:1)

因为您使用非虚拟继承从A派生,A在类型D的每个对象中间接创建两个类型为A的子对象。在执行指向派生到指针到基础的转换时,编译器无法消除您引用哪个子对象的歧义,并发出错误。

为了只为D类型的对象生成一个A类型的子对象,您必须从继承路径D虚拟继承A 1}}派生自class B1: virtual public A { // ... }; class B2: virtual public A, public B1 { };

B2

修改

我尝试在Visual Studio 2010 SP1上编译您的示例,该示例为我提供了关于class B2: public A, public B1 { }; 1>sotest.cpp(18): warning C4584: 'B2' : base-class 'A' is already a base-class of 'B1' 1> sotest.cpp(6) : see declaration of 'A' 1> sotest.cpp(11) : see declaration of 'B1' 定义的警告

A

换句话说,出于某种原因,VC10似乎认为A* a = &b;的继承是冗余的,忽略它。这就是作业class B2编译的原因:A实际上只从B1继承一次(通过D)。 D也不是这样,因为VC10可能没有可忽略的冗余继承,A有效地从B1继承两次(通过B2和{{1} })。

我忽略了VC10以这种方式运行的原因,我不知道是否有编译器选项可以抑制此行为。值得注意的是,GCC 4.7.2和Clang 3.2 拒绝来编译作业A* a = &b;

答案 1 :(得分:1)

对于未来的用户似乎:

我刚刚在GCC 4.7.1和Clang 3.2上尝试过它,除非我使用虚拟继承,否则我会遇到编译器错误。你用的是什么编译器? - 安迪普罗尔

VS2010确实可以编译,但发出一个警告,表明它忽略了B2对A的继承。这就是Row 27工作的原因。我认为这是VS2010的奇怪行为,我不知道是否有办法将其关闭(除了将所有警告视为错误) - Andy Prowl

谢谢@Andy Prowl。