假设钻石继承打破了C++的封装是否正确?



请看下面的代码:

class Base
{
int a;
public:
Base(int b){a =b;}
};
class M1: public virtual Base{
public:
M1(int a): Base(a+10){} // Expect a is increased by 10
};
class M2: public virtual Base{
public:
M1(int a): Base(a+20){} // Expect a is increased by 20
};
class F: public M1, public M2{
public:
F(int a): M1(a-2), M2(a-3), Base( a-10){} // ouch Base constructor called only once and with unexpected value!
};

现在,虽然代码真的很愚蠢,但它突出了一个问题,基本上 M1 和 M2 类都正常工作,假设 Base 处于特定状态(在这种情况下,它增加了 10 或 20)。添加另一个派生类 (F) 会破坏此封装,因为Leaves "a" 处于意外状态,因为它将其减少 10 而不是增加。

M1 和 M2 将访问具有意外值的"a",对我来说,这意味着基本上我破坏了封装,人们不再可以自由更改 M1,M2 类中的代码,因为它最终可能会破坏 F(viceversa 也是真的)。

实际上,我所要求的与

  • 脆弱基类问题

在脆弱的基类问题中,我们有被基类更改破坏的"派生"类,在我的例子中是相反的:

  • 我有一个派生类正在破坏其中一个基类

子对象不拥有其虚拟基础。它可能会与同一最派生对象的其他子对象共享它,该子对象是其所有虚拟基类子对象的最终所有者。

说这破坏了封装,这和说例如 std::shared_ptr 破坏了封装一样正确。在这两种情况下,状态都在多个用户之间共享,而不是隐藏,这正是每个功能的设计目标。

在您的情况下,假设 M1 提供给 Base 的状态是 Base 最终将假设的状态是完全错误的。这只是一个建议,只有在没有压倒一切的情况时才考虑。派生最多的对象最终决定如何初始化其虚拟基础。任何具有有状态虚拟基的类都应该准备好处理这个问题。

最新更新