Search code examples
c++multiple-inheritance

How to call same name virtual functions of parents


#include <stdio.h>  

struct Base
{
    virtual void thatSomething() = 0;
    void doSomething() {thatSomething(); }
};

struct DerOne : Base
{
    virtual void thatSomething() override {std::puts("DerOne"); }
};

struct DerTwo : Base
{
    virtual void thatSomething() override {std::puts("DerTwo"); }
};

struct Joined : DerOne, DerTwo
{
    Joined()
    {
        Base::doSomething();
    }
};

int main()
{
    Joined j;
    return 0;
}

Output:

DerOne

Why is only thatSomething of DerOne called? I expect it to be called of both parent classes of Joined.

@hvd mentioned that with multiple inheritance I have multiple instances of Base.

Also worth mentioning: When I flip the inheritance of Joined (struct Joined : DerTwo, DerOne), I get

DerTwo

as output instead.

Only doing doSomething() in the Joined constructor will give me an error for ambiguity of the function call.

When I use virtual inheritance, I again get an ambiguity error.

If it is not possible to call both functions this way, what other options do I have in order to achieve that with only one line of code that does not address the intermediate classes in the hierarchy or even no line of code implicitly?


Solution

  • The quick fix is simply to have Joined call both, explicitly. (edited to override the virtual function)

    virtual void Joined::thatSomething() override
    {
        DerOne::thatSomething();
        DerTwo::thatSomething();
    }
    

    If that doesn't take care of everthing, then maybe inheritance isn't a good fit. Composition used to be used a lot more, before all the OOP, and it is still powerful.

    If you're expecting a specific thing to happen when you call thatSomething(), but you don't know which one to call, then maybe it's simply not true that Joined is-a DerOne and is-a DerTwo. But it's much easier for Joined to have-a DerOne, and have-a DerTwo, and as many more as you want.

    #include <list>
    #include <memory>
    struct DerHandler
    {
        std::list<std::unique_ptr<DerBase>> handlers;
    
        void addHandler(DerBase *p) { 
            handlers.push_back(std::unique_ptr<DerBase>(p)); 
        }
    
        void doSomething() { 
            for (std::unique_ptr<DerBase> &rp : handlers)
                rp->thatSomething();
        }
    };
    
    struct Joined : DerHandler {
        Joined(){
            addHandler(new DerOne);
            addHandler(new DerTwo);
        }
    };