我如何制作这个非常复杂的继承树

时间:2013-07-04 01:14:43

标签: c++ inheritance

好。所以我处在一个非常复杂的继承树的情况下(我发誓它是合法的)。我不会详细介绍类包含的内容,因为这与我的问题无关。

      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::dataC::A::data而不是D::A::data。我知道我必须以某种方式实现虚拟继承,但我不确定如何。

2 个答案:

答案 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::dataD的重要组成部分。如果没有获得D,则无法继承D::A::data。如果您引用了任何D,那么您还可以访问其D::A::data

听起来你需要将D分成两个类,或者重新设计我们没有看到的部分。

让我重新说一下:D::A::data需要去某事,除非我们知道那是什么,否则这个问题是不可能回答的。 D的实施在E的子对象及其访问data时会看到什么?