2013-01-21 29 views
3

我想一些帮助解释这个phenomenom:为什么这段代码不起作用? (C++ OOP)公共继承

#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

http://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem – Pubby

+0

它不适用于此,否则Row27也不起作用!第27行和第28行有什么区别? – YoniXw

+0

你使用什么编译器?第27行不会在这里编译 –

回答

1

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

为了具有用于D类型的对象生成的A类型的仅一个子对象,则必须从A虚拟沿着继承路径,这使得D使继承从A派生:

class B1: virtual public A 
{ 
    // ... 
}; 

class B2: virtual public A, public B1 
{ 
}; 

编辑:

我试图编译你的例子在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' 

换句话说,由于某种原因,VC10似乎认为从A多余的继承和忽略它。这就是为什么分配A* a = &b;的作业:class B2实际上只从A继承(通过B1)。 D也是如此,因为VC10可能没有要忽略的冗余继承,并且D有效地从A有效继承两次(通过B1和通过B2)。

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

+0

那么为什么Row27中的代码工作?为什么它不需要虚拟继承!? B2和'D'有相同数量的'A'! – YoniXw

+0

@ user1997873:它真的有用吗?我只是在GCC 4.7.1和Clang 3.2上试过它,除非我使用虚拟继承,否则我会遇到编译器错误。你在用什么编译器? –

+0

Visual Studio C++ 2010 Express – YoniXw

1

对于未来用户看来:

我刚在GCC 4.7.1和3.2锵,我得到一个编译错误,除非我用虚拟继承。你在用什么编译器? - Andy Prowl

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

谢谢@Andy Prowl。

相关问题