Search code examples
c++multiple-inheritance

In a diamond inheritance structure, is there a way to cast between the branches?


I have a diamond inheritance structure in my code in which I have a pointer to the bottom object. I tried to case this to a pointer to the left of the two diamond sides, cast it again to the top of the diamond, and again to the right side. But apparently, C++ kind of remembers the order of casting and things don't work as expected. Example code:

#include <iostream>

class A
{
};

class B1 : public A
{
public:
    virtual int Return1() = 0;
};

class B2 : public A
{
public:
    virtual int Return2() = 0;
};

class C : public B1, public B2
{
public:
    virtual int Return1() { return 1; }
    virtual int Return2() { return 2; }
};

int main()
{
    C c;
    B1* b1 = &c;
    A* a = b1;
    B2* b2 = (B2*)a;
    std::cout << "Return2() = " << b2->Return2();
}

This results in Return2() = 1, so apparently this approach is wrong. I know that something like this works in C#, so my question would be: Is there a way in C++ to do what I'm attempting here or - if not - why is this not an option?


Solution

    • As inheritance is not virtual (for A), you have "Y" inheritance (2 A),
    A     A
    |     |
    B1    B2
     \   /
       C
    

    not a diamond (1 A).

    • Avoid C-cast which might result in reinterpret_cast, and most reinterpret_cast usage leads to Undefined Behavior (UB).

    • You might use dynamic_cast in your case to have expected behavior (A need to be polymorphic for that, default virtual destructor does the job):

    class A
    {
    public:
        virtual ~A() = default; // Added to allow dynamic_cast
    };
    
    class B1 : public A
    {
    public:
        virtual int Return1() = 0;
    };
    
    class B2 : public A
    {
    public:
        virtual int Return2() = 0;
    };
    
    class C : public B1, public B2
    {
    public:
        // override used for extra check from compiler.
        int Return1() override { return 1; }
        int Return2() override { return 2; }
    };
    
    int main()
    {
        C c;
        B1* b1 = &c;
        A* a = b1;
        B2* b2 = dynamic_cast<B2*>(a); // C-cast replaced by dynamic_cast
        assert(b2 != nullptr);
        std::cout << "Return2() = " << b2->Return2();
    }
    

    Demo