2017-08-10 3 views
1

J'ai le code suivant en utilisant l'héritage multiple. Le but est d'utiliser deux interfaces comme l'un dans la classe dérivée:Quelle classe de base appelle la méthode dérivée dérivée?

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

Enregistrement des interfaces provoquera un appel asynchrone à on_state_changed. Est-il possible de discerner quelle interface l'appelle?

+1

Si vous avez besoin de l'information, pourquoi ne pas ajouter un paramètre vous indiquant ce dont vous avez besoin? –

+1

Ou simplement évitez d'utiliser l'héritage multiple. – Ron

+0

Je pense que ce [article] (http://www.cprogramming.com/tutorial/multiple_inheritance.html) a quelques informations à ce sujet sous le sous-titre écueil. – Mekicha

Répondre

5

Vous devrez ajouter une couche entre-deux pour désambiguïser. Voici un petit utilitaire qui crée ceux à la volée:

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

Et c'est tout. Ensuite, il est question de la définition de votre classe en termes de cet utilitaire:

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

Je l'ai utilisé un autre paramètre et la surcharge pour faire ce sans canevas, mais la technique elle-même peut aussi être fait en écrivant les classes sur et appeler un fonction virtuelle avec un nouveau nom. La clé est de faire en sorte que l'appel virtuel d'origine (via le pointeur d'interface) atteigne un court thunk qui appelle la fonction désambiguïsée.

0

Je pensais à utiliser des modèles pour désambiguïser aussi, mais je crois que la réponse de @StoryTeller est plus élégante.

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

Alternativement, il est possible de fournir des implémentations distinctes pour les gestionnaires directement dans le code de dérivé:

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: Malheureusement, cette solution est non standard et prise en charge que par les compilateurs Visual C++.

+0

Ce n'est pas la compilation pour moi. Quelle compilateur + version utilisez-vous? – nyarlathotep108

+0

Il est VS 2010. Il devrait être classique C++. Quelle erreur obtenez vous? – jszpilewski

+0

erreur: impossible de définir la fonction membre 'InterfaceA :: on_state_changed' dans 'Derived' void InterfaceA :: on_state_changed (état d'état const) override {} ^ – nyarlathotep108