3

I have 2 base classes (B1 and B2) which are derived from common Base class(B), where they have a common variable (let: int x; from base B), in 1st base x=0, in the 2nd base x=10 (default values given in B1,B2 constructors).

Visually:

class B
{
    int x;

protected:

    B(int x) : x{x}{}
};

class B1 : public B
{
protected:

    B1() : B(0){}
};

class B2 : public B
{
protected:

    B2() : B(10){}
};

Now if I derive one more class:

class D : virtual public B1, virtual public B2
{
public:

    D() : B1{}, B2{}{}
};

Here only one copy of x will be available as per virtual concept, now if I try to access x value with derived class object which instance of x I will get in O/p (x=0 or x=10), and why?

6
  • 2
    Please show actual code. Commented Nov 13, 2014 at 5:54
  • I beleive you cannot instantiate class B1 and B2 because they are abstract due to virtual inheritance.. For more info visit: cprogramming.com/tutorial/virtual_inheritance.html Commented Nov 13, 2014 at 6:05
  • 3
    @ReyRajesh What does virtual inheritance has to do with the abstractness (or not) of a class? Commented Nov 13, 2014 at 6:11
  • 4
    @ReyRajesh What are you going on about? Virtual inheritance doesn't have anything to do with whether a class is abstract or not. Commented Nov 13, 2014 at 6:21
  • 1
    Okay.. I understood wrongly from cprogramming.com/tutorial/virtual_inheritance.html Commented Nov 13, 2014 at 6:26

2 Answers 2

5

In order to use virtual inheritance, base B must be declared as virtual in both B1 and B2. Without that, you have non-virtual inheritance of B.

If you have non-virtual inheritance, then you have two B bases in D, so you can't access x in D without qualifying it as B1::x or B2::x

If you have virtual inheritance, then you only have one B and one x, so the two assignments to it (x=0 and x=10) will happen in whichever order you did them in, and whichever one was later will overwrite the value set by the earlier one (much as with a simple variable x with two assignments).

Sign up to request clarification or add additional context in comments.

7 Comments

Excellent ! The init is done in the ctor of B1 and B2. Is there any guarantee about the order here (f.ex left to rgt because of coma) according to std ?
I don't think the last paragraph about virtual inheritance is correct. The most derived class has to construct the virtual base class, i.e. with a call to the virtual base class's constructor in the member initializer list (if it's not the default constructor, which would be called implicitly). See my answer.
@Chris Dodd, you are right, I want to know what happens when I inherit a class virtually ? (what I mean is if I put one virtual function I a class it will become polymorphic and maintain V.table etc... in the same way what happens when I derive class virtually ? )
@Oguk: While B will be initialized from D, you don't need to do it explicitly -- it will implicitly use the default ctor. The way the OP described his code, he has assignments to x (somewhere), not initializations of it. Assignments can happen anywhere and need not be in constructors.
@Durga: With your edited example, if you change B to be inherited virtually, it won't compile, as there's no default ctor for B, and that's what D tries to (implicitly) use.
|
2

In your setup as you have it, B is not actually inherited virtually, because you would have to declare virtual inheritance for B in both B1 and B2 (it always has to happen at the lowest level if the two "branches" are expected to be merged higher up in the class inheritance hierarchy), i.e.

class B1 : virtual public B
{
protected:

    B1() : B(0){}
};

class B2 : virtual public B
{
protected:

    B2() : B(10){}
};

If you do that, initialization of B would be completely different, because there are special rules for the construction of virtual base classes:

In virtual inheritance, the virtual base class is always initialized by the most derived class. Thus, as you have implemented the constructor of D as

D() : B1(), B2(){}

and therefore don't call your B constructor explicitly, the compiler will assume that you want to call Bs default constructor. But your class B does not have a default constructor, so you would get a compiler error like this:

prog.cpp: In constructor ‘D::D()’:
prog.cpp:31:20: error: no matching function for call to ‘B::B()’
     D() : B1(), B2(){}
                    ^

Therefore, you would have to do something like

class D : public B1, public B2
{
public:

    D() :  B(99), B1(), B2(){}
};

and this also solves your question: The value of x will be whatever the most derived class wants it to be (99 in this case). Thus, there is no ambiguity.

PS: You also see, your question is at the heart of why it makes sense to have the special rule about virtual base class construction by the most derived class.

4 Comments

even if I change the order as 1) D() : B(99), B1(), B2(){} 2)D() : B1(), B2(),B(99) {} -> the value of x will be 99 only. whay there is no effect of B1, B2 here, we are over writing the value of x in B1 and B2 constructor right ?
For virtual inheritance, the constructor of the base class is only called from the most derived class. So, the calls to B's constructor from B1's and B2's constructors are skipped. Note that this would be different if you did plain assignments (x = some_number;) within the constructors of B1 and B2. These would not be skipped. In that case, the order would become important: The constructor of the virtual base class is always executed first, no matter what order you specify them in the list (and the compiler should warn you about your case "2)", where B(99) comes last).
Just a note: I just changed all constructor calls of the type D() : B{99}, B1{}, B2{}{} in my answer to the "traditional" syntax, i.e. D() : B(99), B1(), B2(){} because some versions of gcc seem to have problems with the former. I just posted a question to confirm this is indeed a bug of gcc.
+1 for the explanations about virtual base being intialized by the most derived class, which makes this an excellent and very complete answer !

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.