0

Look at the following code:

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!
};

Now while the code is really stupid, it highlights one problem, basically both classes M1 and M2 to working correctly assumes that Base is in a particular state (in this case it is increased by 10 or 20). Adding another derived class (F) breaks this encapsulation because Leaves "a" in a unexpected state because it decrease it by 10 instead of increasing.

M1 and M2 will access "a" with unexpected value then, to me this means that basically I breaked encapsulation, people is no longer free to change code in M1,M2 classes because it could eventually break F (also viceversa is true).

Actually what I'm asking for is the exact opposite of the

In the fragile base class problem we have "derived" class that is broke by base class changes, in my case it is the opposite:

  • I have a derived class that is breaking one of the base classes.
Community
  • 1
  • 1
CoffeDeveloper
  • 7,961
  • 3
  • 35
  • 69
  • It does not take virtual inheritance to get a derived class to break a base class. Google "brittle base class" to learn more. C++ finally got the `final` keyword, if you don't use it then you'll live to regret it some rainy day. – Hans Passant Apr 04 '17 at 10:21
  • so you want to have 1 Base object, but initialized in 2(or 3?) different ways ? It seems to me that your design has problem. – Andrew Kashpur Apr 04 '17 at 10:29
  • No I don't want it. I was investigating C++ syntax and inheritance mechanism, and I saw that particular behaviour. in one of the demo programs I wrote (all programs of the kind "who get called in this case"). – CoffeDeveloper Apr 04 '17 at 10:31

1 Answers1

2

A subobject doesn't own its virtual base. It potentially shares it with other subobjects of the same most derived object, which is the ultimate owner of all its virtual base class subobjects.

Saying that this breaks encapsulation is no more and no less correct than saying that e.g. std::shared_ptr breaks encapsulation. In both cases the state is shared between several users, not hidden, which is exactly the design objective of each feature.

In your case it would be simply wrong on the part of M1 to assume that the sate it gives to Base is the state that Base will eventually assume. It's merely a suggestion, taken into account only if there are no overriding circumstances. The most derived object ultimately decides how its virtual bases will be initialised. Any class with a stateful virtual base should be ready to handle this.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • So basically a class that is "virtual inheriting" another class, should make no assumption about how that object is initialized, but I see this suggestion nowhere, and there are a lot of "c++ good practices manuals". – CoffeDeveloper Apr 04 '17 at 10:23
  • 1
    @GameDeveloper Count this the first good suggestion then. Do I get a cookie? – n. m. could be an AI Apr 04 '17 at 10:25
  • 1
    @GameDeveloper: Those "good practices manuals" presumably instruct you to avoid virtual inheritance in the first place, which overrides these concerns. – Lightness Races in Orbit Apr 04 '17 at 10:32
  • 1
    @GameDeveloper: (no pun intended) – Lightness Races in Orbit Apr 04 '17 at 10:32
  • 1
    yeah but those manuals most times don't give reasons, I Always try to understand WHY I have to do something, and it happens today I was investigating why I should avoid Diamond Inheritance :). @n.m. ahah yeah you deserve a cookie XD – CoffeDeveloper Apr 04 '17 at 10:33
  • 1
    @GameDeveloper Good for you to ask for the "Why?"! And when you've found an answer to that question, you may well find out that there are valid use cases for almost any programming construct. Including even the dreaded `goto` statement. In my experience, it is not helpful to be religious about anything when programming. You have to be pragmatic and never stop asking yourself whether there is a simpler solution to your problem at hand. – cmaster - reinstate monica Apr 04 '17 at 10:45