0

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

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

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

4

2 回答 2

1
Is this safe?

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

请注意,如果in中没有纯虚方法,则使用path 将始终调用in 中的方法(类似于path),尽管 in 中的实现是预期/有用的。当有数据成员时,这也将起作用,并且在此特定设置中,将使用继承的数据成员 via 。AoverriddenDD->B->AoverriddenBD->C->ACAD->B->A

于 2014-05-10T11:52:11.687 回答
0

你写的不是菱形图案!

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

class B :  virtual public A

class C :  virtual public A

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

请记住,您必须在 D 中手动调用 A 的构造函数。此外,如果 C 或 D 的构造函数调用 A 的构造函数!如果您创建 D 的实例,则不会发生此调用!

于 2014-05-10T13:13:21.257 回答