Diamond(多重继承),没有数据成员

时间:2014-05-10 11:39:42

标签: c++ inheritance multiple-inheritance diamond-problem

假设我们有通常的钻石图案:

class A
{
public:
    virtual char foo() = 0;

    virtual ~A() {} 
};

class B :  public A
{
public:
    virtual char foo() { return 'B';}

    virtual ~B() {}
};

class C :  public A
{
public:
    virtual char foo() { return 'C';}

    virtual ~C() {}
};

class D :  public B,  public C
{
public:

    virtual char foo() { return 'D';}

    virtual ~D() {}
};

请注意,基类A没有任何数据成员。它实际上只是一个纯虚方法的接口。

如果我这样做:

D* d = new D();

A* a = static_cast<A*>(d);

编译器会告诉我,由于有两个A基类,所以转换是不明确的。

但是,如果我这样做:

D* d = new D();

B* b = static_cast<B*>(d); // Or C* c = static_cast<C*>(d); 

A* a = static_cast<A*>(b);

现在我有一个指向我A基类之一的指针,我可以a->foo()

这样安全吗?

我想知道的是,如果我可以进行双向上转换,只需要指向接口(没有数据成员),而不需要虚拟继承的开销。我不打算向下转向指针,也不打算用虚拟方法调用它。

我知道这意味着有两个基类,但由于没有成员,它应该无关紧要,或者是这样吗?

EDIT: 我正在努力寻找实现接口的方法,我想我只需要使用虚拟继承。

假设我有一个类Buffer(接口类),以及一个派生自它的BufferImplementation类。

现在假设我有另一个接口IOBuffer(来自其他接口Buffer),其中IOBufferImplementation类必须从BufferImplementation和{{IOBuffer派生1}} interface。

在我之前的例子中,Buffer是A,BufferImplementation是B,IOBuffer是C,IOBufferImplementation是D。

2 个答案:

答案 0 :(得分:1)

Is this safe?

我是这么认为的。您正在使用两个路径之一从派生类D到基准A。您现在可以安全地使用接口成员

如果A中的纯虚拟方法overridden中不是D,那么使用D->B->A路径只需一条注释始终在overridden中调用B方法(类似于D->C->A路径),尽管C中的实现是有意/有用的。当A拥有数据成员时,这也会有效,在此特定设置中,将使用通过D->B->A继承的数据成员。

答案 1 :(得分:0)

你所写的不是钻石图案!

如果你想要钻石图案,你必须virtual inherit

class B :  virtual public A

class C :  virtual public A

您的版本只是从基类派生线性,这使得D包含基类A的两倍。因此,如果您要求,编译器无法知道应该选择哪个A.如果您使用虚拟导出,则D中只能获得一个A.

请记住,您必须手动调用D中的A的构造函数。如果C或D的构造函数调用A的构造函数!如果您创建D!

的实例,则不会发生此调用