请查看以下代码:
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)会破坏这种封装,因为离开" a"处于意外状态因为它减少10而不是增加。
M1和M2将访问" a"那么,对我而言,这意味着基本上我打破了封装,人们不再可以自由地更改M1,M2类中的代码,因为它最终可能会破坏F (反之亦然)。
实际上我要求的是与完全相反的
在脆弱的基类问题中,我们有"派生"被基类更改破坏的类,在我看来是相反的:
答案 0 :(得分:2)
子对象不拥有其虚拟基础。它可能与同一个派生对象的其他子对象共享它,它是所有虚拟基类子对象的最终所有者。
说这打破了封装,并不比说这样说更正确std :: shared_ptr打破了封装。在这两种情况下,状态在多个用户之间共享,而不是隐藏,这正是每个功能的设计目标。
在你的情况下,在M1的部分假设它给Base的状态是Base最终会假设的状态是完全错误的。它只是一个建议,只有在没有压倒一切的情况下才会考虑到这一点。最派生的对象最终决定如何初始化其虚拟基础。任何具有有状态虚拟基础的类都应该准备好处理它。