6

假设我有 4 节课:

class I { public: virtual void X() = 0; };
class A : public virtual I { public: virtual void X() { } };
class B : public I {  };
class C : public A, public B { };

IB并且C是抽象的,而 asA不是。如果我只是简单地添加到for的virtual继承,则在.IBA::X()I::X()C

但是,我无法更改B.

我的问题:我可以在无法改变的情况下A::X()解决问题吗?我尝试过声明和虚拟化无济于事。我试图没有多余的代码(例如,让 C 声明 X() { A::X(); })。有什么巧妙的技巧吗?I::XCBABC

另外 - 有一些非常像这样的问题,但我找不到任何关于使用virtual继承的讨论。如果我错过了,请指给我一个。

4

3 回答 3

3

您的问题出在 vtable 上。在您当前的代码中,您有两个 - 一个 in A'sI和一个 in B's I。只要仅A虚拟继承I,您就可以使用常规继承并节省开销。如果两者实际上都继承了I,那么您将只有一个Iin实例C,因此只有一个 vtable,并且A::X确实可以覆盖纯 virual I::X

鉴于您无法更改B,您唯一可以处理这两个 vtable 的地方是C. 在我看来,要走的路就是你提到的 - 只需C::X将电话转发到A::X. 那里没有代码重复,而且它C不抽象:

class C : public A, public B {
public:
    virtual void X() { A::X(); }
};

至于虚拟继承,这里肯定有一些。但欢迎你问...

于 2012-07-06T17:39:53.453 回答
2

这很好:什么时候虚拟继承是一个好的设计?

这里的问题是,在 C 中你有两个接口 I。这就是为什么 A::x() 满足它的接口 I - 但它不能从类 B 中抽象出接口 I。对于 C 来说,只有一个接口I - 是将 B 更改为虚拟地从 I 派生 - 这样,来自 A 和来自 B 的 I 接口都将合并为 C 中的一个。你不能更改 B - 所以唯一的方法是添加你正在尝试的冗余代码避免。我的意思是定义 C::X()。

于 2012-07-06T17:40:09.963 回答
1

我能想到的唯一方法是将一个B*(或智能变体)组合成C而不是从它继承,并转发适当的方法。在维护继承的同时你不能这样做,因为编译器不知道I要遵循哪个继承链。

于 2012-07-06T17:35:15.397 回答