Search code examples
c++overridingmultiple-inheritance

Which base class is calling derived overridden method?


I have the following code using multiple inheritance. The purpose is to use two interfaces as one in the derived class:

struct InterfaceA
{
    virtual void register_stuff();
    virtual void on_state_changed( const State state ) = 0;
};

struct InterfaceB
{
    virtual void register_stuff();
    virtual void on_state_changed( const State state ) = 0;
};

struct Derived : InterfaceA, InterfaceB
{
    void register_stuff() override
    {
        InterfaceA::register_stuff();
        InterfaceB::register_stuff();
    }

    void on_state_changed( const State state ) override
    {
        // how can I know who is responding?
    }
};

Registering the interfaces will cause an asynchronous call to on_state_changed. Is it possible to discern which interface is calling it?


Solution

  • You'll have to add a layer in-between to disambiguate. Here's a small utility that creates those on the fly:

    template<class Inteface>
    struct disambiguate : Interface {
      void on_state_changed( const State state ) override final {
        on_state_changed(state, this);
      }
      virtual void on_state_changed( const State &state, disambiguate* ) = 0;
    };
    

    And that's it. Then it's a matter of defining your class in terms of this utility:

    struct Derived : disambiguate<InterfaceA>, disambiguate<InterfaceB>
    {
        void register_stuff() override
        {
            InterfaceA::register_stuff();
            InterfaceB::register_stuff();
        }
    
        void on_state_changed( const State &state, disambiguate<InterfaceA>* ) override
        {
            // Called for A
        }
    
        void on_state_changed( const State &state, disambiguate<InterfaceB>* ) override
        {
            // Called for B
        }
    };
    

    I've used another parameter and overloading to make this templatized, but the technique itself can also be done by writing the classes out and calling a virtual function with a new name. The key is to make the original virtual call (via the interface pointer) reach a short thunk that calls the disambiguated function.