在大多数书籍和文章中,进行多重继承的唯一“安全”(或至少是唯一建议的)方式是使用纯抽象基类(可以称为虚拟接口)进行虚拟继承。
主要原因是为了避免出现钻石问题,因为钻石问题可能会为数据成员的价值或非纯虚函数的实现状态带来歧义。
纯抽象基类不会同时遭受痛苦(没有数据成员,没有非纯虚函数),虚拟继承甚至可以解决基类实际内存地址的歧义。
但是给出这样的解释:如果歧义仅由“状态”的形式(例如,数据成员,静态函数变量)引起,则不是无状态的非抽象类(甚至对于所有“最终”方法也是如此)类同样安全地成为多重继承层次结构中的基类?
我想念什么可能的问题?
PS:如果答案是“如果没有虚拟方法,那么您仍然可以使用合成”:除了学术上的兴趣,我还需要一个成员函数的属性以便能够自由阴影,全局C样式函数,因此我无法通过指向组成对象的指针来访问它们。
答案 0 :(得分:1)
虚拟继承已经已通过避免重复使用非静态成员来实现所需的安全性。变量和函数在这方面是相同的:即使基类是无状态的,但如果它是基类不止一次,则其非静态成员 function 仍然是不确定的。
虚拟继承也可以智能地处理覆盖:
struct B {
virtual ~B()=default;
virtual void f()/*=0*/;
};
struct X : virtual B {};
struct Y : virtual B {
void f() override;
};
struct D : X,Y {};
B& b();
void g() {
b().f(); // calls Y::f
}
B::f
是否是纯虚拟的都没关系。
因此无国籍并不是重要的部分。此外,如果基数是无状态的,则拥有final
成员将防止默认存根实现的最明显用例。 (唯一的其他可能性是依赖于this
的 value ;否则功能可以是静态的。)因此,我不必鼓励使类成为无状态的,因为< / strong>用于虚拟继承(而不是简单地因为将状态最小化通常是一个好主意)。
因此,您正确地认为非纯虚拟功能可以是安全,但这是正确的,即使基准是有状态。当然,多重继承的安全性仍然存在限制,例如,如果重载集接受多个直接基数,则模棱两可。