Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

visiteur, surcharge de méthode virtuelle, et warning de GCC

4 réponses
Avatar
Matthieu Moy
Bonjour,

J'utilise dans un programme C++ le design pattern du visiteur.
Jusqu'ici, tout a l'air de bien marcher. Je viens de découvrir
l'option -Woverloaded-virtual de GCC, qui d'une manière générale me
parait très utile, seulement voila : j'ai une hierarchie de classes de
visiteurs, certaines classes donnent des implementations par défaut,
et d'autres ne surchargent que certaines méthodes. Du coup, le
-Woverloaded-virtual de GCC s'affole.

Le problème reproduit sur un exemple a peu près minimaliste :

#include <iostream>
using namespace std;


struct base;
struct d1;
struct d2;

struct visitor {
virtual void visit(d1 * d) {cout << "d1" << endl;}
virtual void visit(d2 * d) {cout << "d2" << endl;}
};

struct vcaps : visitor {
virtual void visit(d1 * d) {cout << "D1" << endl;}
};

struct base {
virtual void accept(visitor * v) = 0;

};

struct d1 : base {
virtual void accept(visitor * v) {v->visit(this);}
};

struct d2 : base {
virtual void accept(visitor * v) {v->visit(this);}
};

int main () {
d1 d;
d2 dd;
vcaps v;
d.accept(&v);
dd.accept(&v);
}


GCC me dit :

visitor.cpp:11: warning: `virtual void visitor::visit(d2*)' was hidden
visitor.cpp:15: warning: by `virtual void vcaps::visit(d1*)'


Question : est-ce que je risque vraiment quelque chose avec du code
comme ça, ou est-ce que GCC s'affole pour rien ?

Bien sur, si je renomme mes fonctions "visit" en "visit_d1" et
"visit_d2", le warning disparait.

Question 2 : est-ce qu'il vaudrait mieux que je renomme toutes les
fonctions "visit" de mes visiteurs ? Et vous, vous les faites comment
vos visiteurs ?

--
Matthieu

4 réponses

Avatar
Jean-Marc Bourguet
Matthieu Moy writes:

Question : est-ce que je risque vraiment quelque chose avec du code
comme ça, ou est-ce que GCC s'affole pour rien ?


Quel est le pb indique par le warning? Que si on utilise la classe
*derivee* pour faire un appel a la fonction, on ne la fonction
virtuelle n'est pas visible et donc ne sera pas appellee.

Quand est-ce que ca pose un probleme? Si on appelle la fonction a
partie de la classe derivee et que la resolution de surcharge ne
trouve pas (on a un message d'erreur) ou pire trouve un autre membre
(on n'a pas de message mais un comportement different de celui
attentu, en particulier on va avoir un comportement different suivant
qu'on utilise la classe derivee ou la classe de base).

Est-ce que dans le cas du pattern visiteur ca pose un gros probleme?
Generalement non: les appels sont faits a partir de la classe de base.

Le probleme peut avoir lieu pour des membres non virtuels.

Bien sur, si je renomme mes fonctions "visit" en "visit_d1" et
"visit_d2", le warning disparait.

Question 2 : est-ce qu'il vaudrait mieux que je renomme toutes les
fonctions "visit" de mes visiteurs ?


Plus simple:
using visit;

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Matthieu Moy
xavier writes:

En ajoutant

struct vcaps : visitor {
using visitor::visit; // Injecte tous les noms visit de visitor

virtual void visit(d1 * d) {cout << "D1" << endl;}
};



Merci, Je ne connaissais pas.

Il y a une raison pour laquelle ce n'est pas le "comportement" par
défaut de C++ ?

--
Matthieu


Avatar
xavier
En ajoutant

struct vcaps : visitor {
using visitor::visit; // Injecte tous les noms visit de visitor

virtual void visit(d1 * d) {cout << "D1" << endl;}
};


Le warning :
visitor.cpp:11: warning: `virtual void visitor::visit(d2*)' was hidden
visitor.cpp:15: warning: by `virtual void vcaps::visit(d1*)'


n'apparait plus. Et de fait, la méthode visit(d2*) n'est plus cachée.

Question : est-ce que je risque vraiment quelque chose avec du code
comme ça, ou est-ce que GCC s'affole pour rien ?


Comme le warning l'indique, un appel du type :

//...
d2 b;
vcaps v;
v.visit(&b); // [1]
// ...

va échouer avec l'erreur :
visitor.cpp:35: error: no matching function for call to `vcaps::visit(d2*)'
visitor.cpp:16: note: candidates are: virtual void vcaps::visit(d1*)

Si tu n'ajoute pas la ligne "using visitor::visit"

xavier

Avatar
Jean-Marc Bourguet
Matthieu Moy writes:

Il y a une raison pour laquelle ce n'est pas le "comportement" par
défaut de C++ ?


La regle correspond exactement a ce qui est fait pour des blocs
imbriques: on ne va voir dans le bloc englobant (resp dans les classes
de base) que si on ne trouve pas dans le bloc courant (resp dans la
classe derivee).

On peut arguer en faveur d'une autre regle, mais utiliser celle-la a
l'avantage de ne pas ajouter encore une autre regle de recherche des
noms et avait l'avantage, maintenant vraissemblablement disparu a
cause d'autres changements, d'eviter des problemes (pour les details
historiques, voir The Design And Evolution of C++, 3.5.3).

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org