41 votes

Résolution des surcharges en C++

Dans l'exemple suivant, pourquoi dois-je utiliser explicitement l'instruction b->A::DoSomething() plutôt que juste b->DoSomething() ?

La résolution des surcharges du compilateur ne devrait-elle pas déterminer la méthode dont je parle ?

J'utilise Microsoft VS 2005. (Note : l'utilisation de virtual n'aide pas dans ce cas).

class A
{
  public:
    int DoSomething() {return 0;};
};

class B : public A
{
  public:
    int DoSomething(int x) {return 1;};
};

int main()
{
  B* b = new B();
  b->A::DoSomething();    //Why this?
  //b->DoSomething();    //Why not this? (Gives compiler error.)
  delete b;
  return 0;
}

43voto

Konrad Rudolph Points 231505

Les deux "surcharges" ne sont pas dans la même portée. Par défaut, le compilateur ne considère que la plus petite portée de nom possible jusqu'à ce qu'il trouve une correspondance de nom. La correspondance des arguments est faite ensuite . Dans votre cas cela signifie que le compilateur voit B::DoSomething . Il essaie ensuite de faire correspondre la liste des arguments, ce qui échoue.

Une solution serait de tirer vers le bas la surcharge à partir de A en B Le champ d'application de la directive :

class B : public A {
public:
    using A::DoSomething;
    // …
}

14voto

Pieter Points 9200

La résolution des surcharges est l'une des parties les plus laides du C++.

En gros, le compilateur trouve un nom correspondant à "DoSomething(int)" dans la portée de B, voit que les paramètres ne correspondent pas, et s'arrête avec une erreur.

Ce problème peut être résolu en utilisant la classe A::DoSomething dans la classe B.

class A  
{  
  public:  
    int DoSomething() {return 0;}
};  

class B : public A  
{  
  public:  
    using A::DoSomething;
    int DoSomething(int x) {return 1;} 
};   

int main(int argc, char** argv)
{
  B* b = new B();  
  // b->A::DoSomething();    // still works, but...
  b->DoSomething();    // works now too
  delete b;  
  return 0;
}

5voto

Lehane Points 6776

Non, ce comportement est présent pour s'assurer que vous ne vous faites pas prendre à hériter de classes de base distantes par erreur.

Pour contourner ce problème, vous devez indiquer au compilateur la méthode que vous souhaitez appeler en plaçant un using A::DoSomething dans la classe B.

Voir cet article pour un aperçu rapide et facile de ce comportement.

5voto

James Curran Points 55356

La présence d'une méthode dans une classe dérivée masque toutes les méthodes portant le même nom (indépendamment des paramètres) dans les classes de base. Ceci est fait pour éviter des problèmes comme celui-ci :

class A {} ;
class B :public A
{
    void DoSomething(long) {...}
}

B b;
b.DoSomething(1);     // calls B::DoSomething((long)1));

plus tard, quelqu'un change de classe A :

class A
{
    void DoSomething(int ) {...}
}

maintenant, soudainement :

B b;
b.DoSomething(1);     // calls A::DoSomething(1);

En d'autres termes, si cela ne fonctionnait pas ainsi, un changement sans rapport avec une classe que vous ne contrôlez pas (A), pourrait affecter silencieusement le fonctionnement de votre code.

3voto

Arkadiy Points 10567

Cela a quelque chose à voir avec le fonctionnement de la résolution des noms. Fondamentalement, nous trouvons d'abord la portée d'où provient le nom, puis nous rassemblons toutes les surcharges pour ce nom dans cette portée. Cependant, dans votre cas, la portée est la classe B, et dans la classe B, B::DoSomething cache A::DOSomething :

3.3.7 Masquage du nom [basic.scope.hiding].

... [snip]...

3 Dans une définition de fonction membre, la déclaration d'un nom local cache la déclaration d'un membre de la classe portant le même nom ; voir classe.scope.basique . La déclaration d'un membre dans une classe dérivée ( classe.dérivée ) cache la déclaration d'un membre d'une classe de base du même nom. du même nom ; voir recherche de membres de classe .

En raison de la dissimulation du nom, A::DoSomething n'est même pas pris en compte pour la résolution des surcharges.

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