我有一个钻石问题,看起来像这样:
__ A
/ |\
| B | \
v|/v v\|v \v
B2 B3 C
\v /v /
B4 /
\ /
D我尝试了许多方法来实现最好的虚拟继承,以避免重复,但我找不到解决方案。A类包含一个位置。以下是示例输出:
Call: A() position pointer is: 0x2203be8
Call: B()
Call: B2() position pointer is: 0x2203be8
Call: B3() position pointer is: 0x2203be8
Call: C() position pointer is: 0x2203a28
Call: B4() position pointer is: 0x2203be8
Call: D() position pointer is: 0x2203a28为什么D和C没有相同的位置指针?为什么这个A::position没有构造函数?我应该做什么虚拟继承来解决这个问题呢?谢谢。
编辑:
下面是一个代码示例:
class A;
class B;
class B2 : public virtual B, public virtual A;
class B3 : public virtual B, public virtual A;
class C : public virtual A;
class B4 : public virtual B2, public virtual B3;
class D : public B4, public C;编辑2:为了生成输出,我将此代码放入每个构造函数中:
A::A()
{
std::cerr << "Call: A() position pointer is: " << &_position << std::endl;
}发布于 2012-11-17 04:38:42
既然你说下面的代码,它在我的实现上工作,对你来说是坏的,那么显然代码不是问题。问题出在您的设置中的其他方面;可能是编译器错误。您应该缩小导致问题的其他原因的范围;由于代码本身被排除为问题,因此最好的下一步可能是更新您的编译器。
在任何情况下,这使得这个问题对你的设置来说是非常特定的。如果你确实找到了一个可能适用于其他人的解决方案,那么你应该回来张贴它。在此之前,我将投票结束这个问题。
我在试着重现你的问题。下面是我使用的代码:
#include <iostream>
struct A { int a; };
struct B { int b; };
struct B2 : virtual B, virtual A {};
struct B3 : virtual B, virtual A {};
struct B4 : virtual B2, virtual B3 {}; // these virtuals are unnecessary in this case...
struct C : virtual A {};
struct D : B4, C {};
int main() {
D d;
std::cout << &((B4*)&d)->a << '\n';
std::cout << &((B3*)(B4*)&d)->a << '\n';
std::cout << &((B2*)(B4*)&d)->a << '\n';
std::cout << &((A*)(B2*)(B4*)&d)->a << '\n';
std::cout << &((A*)(B3*)(B4*)&d)->a << '\n';
std::cout << &((C*)&d)->a << '\n';
std::cout << &((A*)(C*)&d)->a << '\n';
}但我得到的结果与预期一致,其中每个对象的a成员都是相同的。如果我也在构造函数中打印地址,我也会得到相同的结果:http://ideone.com/8FdQ1O
如果我稍作修改,并从C的定义中删除了virtual关键字:
...
struct C : A {};
...(version using constructors)
然后我确实看到了你所描述的问题,C有它自己的A子对象,不同于B2,B3和B4使用的虚拟对象。
您确定在所有需要的地方都使用了virtual关键字吗?您显示的结果似乎表明您在某处遗漏了它。另外,我注意到您显示的输出没有反映与您显示的代码片段相同的构造函数顺序;输出首先显示A(),但代码表明应该首先执行B()。
虚拟继承的工作方式是,对于继承树中任何位置虚拟继承的每个类型,大多数派生类型都将包含一个虚拟子对象。此外,派生最多的类型将包含非虚拟继承的每个实例的子对象:
struct A {};
struct B : virtual A {};
struct C : A, B {};
struct D : virtual A, C {};
struct E : A, D {};
struct F : virtual A, E {};
struct G : A, F {};
G g;g总共包含四个A子对象;每次A是非虚拟继承时(在C、E和G中)一个子对象,在所有A虚拟继承时(在B、D和<代码>d17中)一次。
发布于 2012-11-17 03:25:07
你现在有什么代码?看起来解决方案是:
class D;
class C : public virtual D;
class B4 : public virtual D;
class B2 : public virtual B4;
class B3 : public virtual B4;
class B : public B2, public B3;
class A : public B2, public B3, public C;根据你的图表。如果我读错了,A是基数,而不是D,那么它需要看起来像这样:
class A;
class B;
class B2 : public virtual B, public virtual A;
class B3 : public virtual B, public virtual A;
class C : public virtual A;
class B4 : public virtual B2, public virtual B3;
class D : public B4, public C;发布于 2012-11-17 03:54:33
为什么D和C没有相同的位置指针?
因为您从B4和C非虚拟地继承了D,这意味着您有两个A的副本(和两个指针)。
D构造函数中的&B4::position与&C::position不同
为什么这个A::position没有构造函数?
不知道,有没有可能你的A类有多个构造函数,并且默认静默构造函数是由C::C()调用的?
我应该做什么虚拟继承来解决这个问题?
将所有内容设置为虚拟。这意味着你需要显式地调用D::D()中的每个构造函数(即A::A( ),B::B(),B2::B2(),B3::B3(),C::C() )。
Tbh我认为你应该重新考虑你的等级制度。我不知道细节,但似乎通过组件设计,您的问题有了一个更清晰的解决方案。
https://stackoverflow.com/questions/13423012
复制相似问题