哪个基类调用派生重写方法?

时间:2017-08-10 12:18:47

标签: c++ override multiple-inheritance

我有以下使用多重继承的代码。目的是在派生类中使用两个接口作为一个接口:

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?
    }
};

注册接口将导致对on_state_changed的异步调用。是否可以辨别哪个接口正在调用它?

3 个答案:

答案 0 :(得分:5)

您必须在中间添加一个图层才能消除歧义。这是一个小型实用程序,可以动态创建它们:

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;
};

就是这样。然后根据这个实用程序来定义你的类:

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
    }
};

我已经使用了另一个参数和重载来使这个模板化,但是技术本身也可以通过编写类并使用新名称调用虚函数来完成。关键是使原始虚拟调用(通过接口指针)到达调用消除歧义的函数的短thunk。

答案 1 :(得分:2)

或者,可以直接在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        
        }
  };

编辑:不幸的是,这个解决方案是非标准的,只有Visual C ++编译器支持。

答案 2 :(得分:0)

我在考虑使用模板来消除歧义,但我相信@StoryTeller的答案更优雅。

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
    }
};