好。所以我处在一个非常复杂的继承树的情况下(我发誓它是合法的)。我不会详细介绍类包含的内容,因为这与我的问题无关。
A<-D
/| |
/ | |
B | |
\ | |
\| |
C |
\ |
\|
E
到目前为止,继承如下。
class A
{
int data;
...
};
class B: public A {...};
class C: public A, public B {...};
我希望C对A的实例有两次,所以我不使用虚拟继承。但是,我希望E类只能继承C::B::A::data
和C::A::data
而不是D::A::data
。我知道我必须以某种方式实现虚拟继承,但我不确定如何。
答案 0 :(得分:3)
如果你环顾四周,你会发现一些关于虚拟继承的详细讨论,特别是当你结合虚拟和正常继承时会发生什么。
我有代码,我认为会创建你所描述的层次结构,但要预先警告:它不会在OS X上链接。它编译得很好,但是我得到了一些非常不寻常的未定义符号。
需要注意的是,混合虚拟和非虚拟继承时很难获得某些基类。为了解决这个问题,我在任何需要虚拟继承的地方添加了另一层。然后该层可以提供唯一命名的访问器。这是通过Virtualize模板完成的。
我很想知道这是否会让其他编译器感到困惑:
#include <cstdio>
template<class OnType,class UniqueType>
class Virtualize : public virtual OnType
{
public:
inline OnType &resolve() { return *this; }
};
class A
{
public:
A(int data): m_aData((data << 4) | 0x0A)
{
printf("Constructed A(%X)\n",m_aData);
}
A();
virtual ~A()
{
printf("Destructing A(%X)\n",m_aData);
}
int m_aData;
};
class B: public A
{
public:
B(int data): m_bData((data<<4) | 0x0B),
A((data<<4) | 0x0B)
{
printf("Constructed B(%X)\n",m_bData);
}
virtual ~B()
{
printf("Destructing B(%X)\n",m_bData);
}
A &getBsA() { return *this; }
int m_bData;
};
class C: public Virtualize<A,C>,
public B
{
public:
C(int data): A((data<<4) | 0x0C),
B((data<<4) | 0x0C),
m_cData((data<<4) | 0x0C)
{
printf("Constructed C(%X)\n",m_cData);
}
virtual ~C()
{
printf("Destructing C(%X)\n",m_cData);
}
A &getCsA() { return Virtualize<A,C>::resolve(); }
int m_cData;
};
class D: public Virtualize<A,D>
{
public:
D(int data): m_dData((data<<4) | 0x0D),
A((data<<4) | 0x0D)
{
printf("Constructed D(%X)\n",data);
}
virtual ~D()
{
printf("Constructed D(%X)\n",m_dData);
}
A &getDsA() { return Virtualize<A,D>::resolve(); }
int m_dData;
};
class E: public C, public D, public Virtualize<A,E>
{
public:
E(int data): A((data<<4) | 0x0E),
C((data<<4) | 0x0E),
D((data<<4) | 0x0E),
m_eData((data<<4) | 0x0E)
{
printf("Constructed E(%X)\n",m_eData);
}
virtual ~E()
{
printf("Destructing E(%X)\n",m_eData);
}
A &getEsA() { return Virtualize<A,E>::resolve(); }
int m_eData;
};
int main( int argc, char **argv )
{
E e(0);
printf("E::B::A::m_aData = %X\n",e.getBsA().m_aData);
printf("E::C::A::m_aData = %X\n",e.getCsA().m_aData);
printf("E::D::A::m_aData = %X\n",e.getDsA().m_aData);
printf("E::E::A::m_aData = %X\n",e.getEsA().m_aData);
C c(0);
printf("C::B::A::m_aData = %X\n",c.getBsA().m_aData);
printf("C::A::m_aData = %X\n",c.getCsA().m_aData);
return 0;
}
感兴趣的是我在链接阶段遇到了这些问题:
Undefined symbols for architecture x86_64:
"std::terminate()", referenced from:
_main in cc6nOq3n.o
D::~D() in cc6nOq3n.o
D::~D() in cc6nOq3n.o
D::D(int) in cc6nOq3n.o
B::~B() in cc6nOq3n.o
B::~B() in cc6nOq3n.o
B::~B() in cc6nOq3n.o
...
"vtable for __cxxabiv1::__class_type_info", referenced from:
typeinfo for Ain cc6nOq3n.o
NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
"vtable for __cxxabiv1::__si_class_type_info", referenced from:
typeinfo for Din cc6nOq3n.o
typeinfo for Bin cc6nOq3n.o
NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
"vtable for __cxxabiv1::__vmi_class_type_info", referenced from:
typeinfo for Virtualize<A, E>in cc6nOq3n.o
typeinfo for Virtualize<A, D>in cc6nOq3n.o
typeinfo for Virtualize<A, C>in cc6nOq3n.o
typeinfo for Cin cc6nOq3n.o
typeinfo for Ein cc6nOq3n.o
NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
"operator delete(void*)", referenced from:
A::~A() in cc6nOq3n.o
A::~A() in cc6nOq3n.o
A::~A() in cc6nOq3n.o
Virtualize<A, E>::~Virtualize()in cc6nOq3n.o
Virtualize<A, E>::~Virtualize()in cc6nOq3n.o
Virtualize<A, D>::~Virtualize()in cc6nOq3n.o
Virtualize<A, D>::~Virtualize()in cc6nOq3n.o
...
"___gxx_personality_v0", referenced from:
Dwarf Exception Unwind Info (__eh_frame) in cc6nOq3n.o
答案 1 :(得分:1)
D::A::data
是D
的重要组成部分。如果没有获得D
,则无法继承D::A::data
。如果您引用了任何D
,那么您还可以访问其D::A::data
。
听起来你需要将D
分成两个类,或者重新设计我们没有看到的部分。
让我重新说一下:D::A::data
需要去某事,除非我们知道那是什么,否则这个问题是不可能回答的。 D
的实施在E
的子对象及其访问data
时会看到什么?