5 votes

Mise en œuvre de fonctions virtuelles pures avec héritage multiple

Supposons qu'il y ait cette interface :

class A{  
 public:  
  virtual foo()=0;  
};

Et une classe B qui implémente cette interface :

class B:public A{    
 public:   
  virtual foo(){} //Foo implemented by B   
}

Enfin, une classe C qui a des classes A y B comme classes de base :

Class C : public A, public B {
};

Ma question est la suivante : existe-t-il un moyen de dire au compilateur que l'implémentation pour foo est celui de la classe B sans faire un appel explicite à B::foo() ?

3voto

tmpearce Points 8306

Comme @BenVoigt l'a souligné dans les commentaires, la réponse ci-dessous ne fonctionne qu'en raison d'un bogue dans g++ (ce qui signifie qu'il n'est pas garanti qu'elle continue à fonctionner, et elle n'est certainement pas portable). Ainsi, bien qu'elle puisse faire ce que vous voulez si vous utilisez un compilateur particulier (bogué), ce n'est pas une option que vous devriez utiliser.

Faites utiliser héritage virtuel cependant.


Ce n'est pas exactement le scénario que le code dans la question implique, mais la phrase

Ma question est la suivante : existe-t-il un moyen d'indiquer au compilateur que l'élément que l'implémentation de foo est celle de la classe B sans faire un appel appel explicite à B::foo() ?

semble demander une syntaxe permettant de distinguer plusieurs versions de base d'une fonction sans utiliser l'attribut :: qualificatif.

Vous pouvez le faire avec le using directive :

#include <iostream>
class A {
public:
A(){}
virtual void foo(){std::cout<<"A func";}
};

class B: virtual public A {
  public:
  B(){}
  virtual void foo(){std::cout<<"B func";}
};
class C:virtual public A, virtual public B {
    public:
    C(){}
    using A::foo; // tells the compiler which version to use
                   // could also say using B::foo, though this is unnecessary
};

int main() {
    C c;
    c.foo(); // prints "A func"
    return 0;
}

Bien sûr, le code lui-même dans la question ne l'exige pas du tout, comme les autres réponses l'ont souligné.

2voto

Ben Voigt Points 151460

Il suffit d'utiliser l'héritage virtuel, de sorte que le A fourni par B est le même objet que celui utilisé dans C .

Ou écrire class C : public B ... il sera implicitement utilisable en tant que A de toute façon, via la classe de base B .


Avant que la question ne soit modifiée :

B::foo n'est pas compatible avec A::foo .

La signature requise est

ReturnType /* missing from question */ foo(A* const this /* this parameter is implicit */);

Pero B::foo a la signature

ReturnType foo(B* const this);

Un site A* qui sera transmise à la fonction virtuelle, n'est pas une B* ce que la mise en œuvre exige. Si B hérité de A alors le compilateur génère B::foo d'accepter un A* const subobject et trouver le B* const this à partir de ce pointeur de sous-objet. Mais B::foo n'a pas connaissance de la relation en C .

0voto

Timo Geusch Points 16952

Comme vous avez deux classes de base dans votre exemple (ce qui pourrait être un problème de conception/une odeur de conception, je vérifierais cela), vous devez appeler explicitement l'implémentation que vous recherchez, que ce soit A::foo() o B:foo() .

Si tout ce que B fait est de fournir l'implémentation de foo() J'envisagerais de déplacer l'implémentation dans A (on peut fournir une implémentation pour une fonction virtuelle pure) mais même dans ce cas, il faudrait l'appeler via son nom qualifié.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X