1

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?

nyarlathotep108
  • 5,275
  • 2
  • 26
  • 64

3 Answers3

5

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.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
2

Alternatively it is possible to provide separate implementations for handlers directly in the code of Derived:

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

        void InterfaceA::on_state_changed( const State state ) override
        {
            // responding A
        }

        void InterfaceB::on_state_changed( const State state ) override
        {
            // responding B        
        }
  };

EDIT: Unfortunately this solution is nonstandard and supported only by Visual C++ compilers.

jszpilewski
  • 1,632
  • 1
  • 21
  • 19
0

I was thinking about using templates for disambiguating too, but I belive @StoryTeller 's answer is more elegant.

struct InterfaceA
{
    virtual void register_stuff();  // calls on_state_changed<InterfaceA>()

    template <typename Interface>
    virtual void on_state_changed( const State state ) = 0;
};

struct InterfaceB
{
    virtual void register_stuff();  // calls on_state_changed<InterfaceB>()

    template <typename Interface>
    virtual void on_state_changed( const State state ) = 0;
};

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

    template <typename Interface>
    void on_state_changed( const State state ) override
    {
        // how can I know who is responding?
        // : "Interface" is responding
    }
};
tuket
  • 3,232
  • 1
  • 26
  • 41