多重继承求解抽象类

Multiple inheritance to solve abstract classes

本文关键字:抽象类 多重继承      更新时间:2023-10-16

>假设我有 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 { };

IBC是抽象的,而A则不是。如果我只是在BI继承中添加virtual,那么A::X() C中解析I::X()

但是,我无法更改B的来源。

我的问题:我可以在不更改B的情况下A::X()解决C I::X吗?我试图宣布AB是虚拟的,但C无济于事。我试图没有多余的代码(例如,让 C 声明 X() { A::X(); })。有什么巧妙的黑客吗?

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

您的问题出在 vtables 上。在你当前的代码中,你有两个 - 一个在AI中,一个在BI中。只要只有A实际上继承I,您也可以使用常规继承并节省开销。如果两者都虚拟继承I那么你在C中只有一个I实例,因此只有一个vtable,A::X确实可以涵盖纯的虚拟I::X

鉴于您无法更改B,您唯一可以照顾两个vtable的地方是C。在我看来,要走的路就是你提到的 - 只需C::X转发对A::X的呼吁.那里没有代码重复,它使C非抽象:

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

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

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

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

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