1

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

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

4

2 回答 2

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
于 2013-07-04T04:19:18.367 回答
1

D::A::data是 的一部分D。如果D没有获得D::A::data. 如果您有对 any 的引用D,那么您也有访问它的方法D::A::data

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

让我换个说法:D::A::data需要去某事,除非我们知道那是什么,否则这个问题是不可能回答的。D当它是它的子对象E并访问它时,它的实现会看到什么data

于 2013-07-04T01:42:20.503 回答