Search code examples
c++multiple-inheritancediamond-problem

Multiple virtual inheritance C++


I have a problem with multiple inheritance and it would be great if someone could help me out. I am programming a situation which ultimately boils down to something similar to this

    class A {
public:
    A(){}
    virtual ~A() = 0;
    virtual void print()=0;
};
A::~A(){}

class B: public virtual A {
public:
    B():A(){}
    virtual ~B() = 0;
    virtual void print() {
        cout << "Hello" << endl;
    }
};
B::~B(){}

class C: public virtual A {
public:
    C():A(){}
    virtual ~C() = 0;
    virtual void print () {
        cout << "Bye" << endl;
    }
};
C::~C(){}

class D: public B, public C {
public:
    D():B(),C(){}
    virtual ~D(){}
    virtual void print(){}
};

int main()
{
    D d;
    A* a = &d;
    a->B::print(); //The statement leads to errors
    a->C::print(); //The statement leads to errors
}

I need to access the the implementation of the virtual function in class B and class C. Is there a way to do this?


Solution

  • To understand this, ignore the inheritance for a second:

    1. Class 'A' doesn't has a print method
    2. Class 'B' and 'C' have their own printing methods
    3. Class 'D' has no printing methods by itself.

    Now add the inheritance to the equation:

    1. Class 'D' inherits 'B' and 'C', so it has both printing methods
    2. Class 'B' and 'C' inherits 'A', but as 'A' has no printing methods, they still have the same methods
    3. Class 'A' has no printing methods.

    When you cast A* a = &d, you are transforming a class with two printing methods to a class without printing methods. Thanks to the power of inheritance, the 'A' class printing method is now overloaded by the one in 'D' class, but 'a' variable is still an 'A' class (with overloads from 'D'). As 'A' doesn't inherits 'B' or 'C', it doesn't knows what they are. Reason why you are getting the error when trying to use them.

    A solution to this would be simply not casting 'D' to 'A':

    int main() {
        D d;
        d.B::print(); //Hello
        d.C::print(); //Bye
    }
    

    Also, if you need to cast 'D' to 'A', you should upcast it to B or C accordingly:

    int main() {
        D d;
        A* a = &d;
        dynamic_cast<B*>(a)->B::print();
        dynamic_cast<C*>(a)->C::print();
    }
    

    Or a 1 dynamic cast version:

    int main() {
        D d;
        A* a = &d;
        D* dptr = dynamic_cast<D*>(a);
        dptr->B::print();
        dptr->C::print();
    }
    

    In other words, you must upcast 'a' to something that inherits 'C' and 'B' before using 'C' and 'B' respectively