1

I've heard that using the virtual keyword solves the diamond problem.

However, when I did this:

#include <iostream>

using namespace std;

class A {
public:
    A(int x = 100) {
        num = x;
    }
protected:
    int num;
}; 

class B1 : virtual public A{
public:
    B1(int x = 50) : A(2*x) {
    }
};
class B2 : virtual public A{
public:
    B2(int x = 50) : A(2*x) {
    }
};
class C : public B1, public B2 {
public:
    C(int x = 75) : B1(2*x), B2(2*x) {};
    int getData(){ return num; } 
};

int main() {
    C c(10);

    cout << c.getData(); 
    cin.get();
    return 0;
}

It displays the output as 100 instead of what I expected, i.e. 40. Why?

B-Mac
  • 557
  • 2
  • 14
  • 2
    A virtual base class is initialized in the *most derived class* (the type of the actual object you create). Since there's no initializer for `A` in `C`, the argument of `A`'s constructor defaults to 100. – dyp Apr 21 '15 at 20:38
  • Or any base class for that matter? – B-Mac Apr 21 '15 at 20:39
  • I'm sorry, I don't understand what you're referring to. – dyp Apr 21 '15 at 20:39
  • Forget the diamond. If B inherits A and C inherits B and I only initialize B from C's constructor, then does A get set to default again, i.e. 100? – B-Mac Apr 21 '15 at 20:41
  • 2
    A class initializes all its non-virtual direct base classes (and, if it's the most-derived type, also all its virtual base classes). That is, if `B` inherits from `A` nonvirtually, then `B` initializes its *`A` base class subobject*. If `C` inherits from `B`, then `C` does *not* initialize `B`'s *`A` base class subobject*. – dyp Apr 21 '15 at 20:43
  • Related/duplicate: http://stackoverflow.com/q/10534228/ – dyp Apr 21 '15 at 20:46
  • @dyp. Please post an answer. – Barry Apr 21 '15 at 20:46
  • 1
    @Barry I'd rather wield my Mjölnir. Except it's so heavy and I'm kinda tired ;) – dyp Apr 21 '15 at 20:47

1 Answers1

2

When you use virtual inheritance, you are guaranteed to have one single instance of the common base class (cite); therefore, B1 and B2 cannot have their own instance of A, but they will share a single instance with C. For instance, if you define C's constructor as follows:

C(int x = 75) : B1(2*x), B2(2*x), A(x) {};

you'll see your code outputs 10. The key is in what @dyp has commented:

the common base class is initialized in the most derived class

(Of course in the example above it doesn't make any sense to have all B1, B2 and A in the initializer list, as having Awill suffice).

Яois
  • 3,838
  • 4
  • 28
  • 50