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

Diamond (multiple inheritance) with no data members

本文关键字:多重继承 Diamond 数据成员      更新时间:2023-10-16

假设我们有通常的菱形图案:

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类,它必须派生自BufferImplementationIOBuffer接口。

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

Is this safe?

我想是的。您正在使用从派生类D到基本A的两条路径之一。您现在可以安全地使用接口成员

请注意,如果A中有纯虚拟方法而不是D中的overridden,则使用D->B->A路径将始终调用B中的overridden方法(类似于D->C->A路径(,尽管C中的实现是有意的/有用的。当A具有数据成员时,这也将起作用,并且在该特定设置中,将使用通过D->B->A继承的数据成员。

您所写的不是菱形图案!

如果你想把这个做成菱形图案,你必须virtual inherit

class B :  virtual public A

class C :  virtual public A

你的版本只是从基类中线性派生,这使得D包含基类A的两倍。因此,如果你要求,编译器没有机会知道应该选择哪个A。如果你用虚拟派生,你在D中只得到一个A。

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