Tuesday, October 2, 2007

Diamonds


Suppose the following class hierarchy : (If you don't know what virtual inheritance means read this).

class A { };
class B1 : public virtual A { };
class B2 : public virtual A { };
class C : public B1, public B2 { };

Now suppose A has a non-trivial constructor, for instance like this:

class A {
public:
    A(int i) { /* ... */ }
};

Because B1 and B2 may disagree on how A must be initialized, A must be initialized from C. This might look like this:

class C {
    C() : A(42) { }
};

In my special case, B1 and B2 are meant to be used within the diamond only. But the compiler does not know this. It could be that another compilation unit defines a class which inherits from B1 without creating a diamond. In this case B1 must initialize A. So B1 needs to call A's constructor. This looks like this:

class A { 
public:
    A(int i) { /* ... */ }
};
class B1 : public virtual A { 
public:
    B1() : A(0) { }
};
class B2 : public virtual A { 
public:
    B2() : A(0) { }
};

class C : public B1, public B2 { 
public:
    C() : A(42) { }
};

Without going into much detail, in the case I encountered there is no meaningful value B1 or B2 could initialize A with. Not only that I have to define an initializer which is never called, I must find some I-don't-really-mean-it value to not initialize A with. What a mess.

Alternatively you could define a default constructor for A which is never called. Perhaps like this:

class A {
    A(int i) { /* ... */ }
    A() { assert(false); }
};

which is not really better.
Well, what should I say, this is C++...

No comments:

Post a Comment