如果你环顾四周,你会发现一些关于虚拟继承的详细讨论,特别是当你结合虚拟继承和普通继承时会发生什么。
我有一些代码,我认为它创建了您所描述的层次结构,但请注意:它不会在 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