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

Fonctions cachées, méthodes virtuelles

9 réponses
Avatar
Christophe Brun
Messieurs dames, bien le bonsoir.

Je chercheà éclaircir le point suivant, concernant le problème du masquage
des noms :
Soit le code (compilé sur C++Builder 5) :

class A
{
public :
virtual ~A() {}
virtual void fct() { cout << "A::fct()" << endl; }
virtual void fct( int ) { cout << "A::fct( int )" << endl; }
} ;

class B : public A
{
public :
virtual void fct( int ) { cout << "B::fct( int )" << endl; }
// [C++ Avertissement] Main.cpp(40): W8022 'B::fct(int)' cache une
fonction virtuelle 'A::fct()'
};

void Nommage()
{
A a;
B b;

A* pa = &a;
A* pb = &b;

pa->fct();
pa->fct( 10 ) ;
pb->fct() ;
pb->fct( 10 ) ;
// b.fct();
// [C++ Erreur] Main.cpp(57): E2193 Trop peu de paramètres dans l'appel à
'B::fct(int)'
b.fct( 10 );
}

Le fait que la déclaration de fct dans B cache l'accès à fct dans A
s'exprime tout à fait normalement sous la forme d'une erreur de compilation
(ligne de code et messages du compilateur portés en commentaires sur le code
ci-dessus). Ce comportement est conforme à la norme (points 3.3.7.3 et 10.2
du Standard).
Je remarque par contre que l'accès à A::fct() n'est pas caché au compilateur
pour la ligne

pb->fct() ;

qui non seulement compile, mais encore fournit les résultats attendus
(sortie console = "B::fct(int)").

Je suppose qu'en l'occurrence, le problème du masquage des noms est
contourné par le compilateur grâce au recours à la table des méthodes
virtuelles.

Ma question est : pouvez-vous confirmer cette hypothèse ?
Questions subsidiaires :
- ce comportement est-il implémenté dans le Standard (je n'ai pas trouvé de
référence, mais l'ouvrage est assez gros pour que je puisse y louper des
infos) ?
- si oui, où ?
- comment interagissent la recherche des noms (name lookup) et le traitement
du polymorphisme lors de la phase de compilation (priorités, résolution des
conflits, etc... toute info est la bienvenue) ?

9 réponses

Avatar
Christophe Lephay
"Christophe Brun" a écrit dans le message de
news:3f1c4588$0$9626$
Messieurs dames, bien le bonsoir.

Je chercheà éclaircir le point suivant, concernant le problème du masquage
des noms :
Soit le code (compilé sur C++Builder 5) :

class A
{
public :
virtual ~A() {}
virtual void fct() { cout << "A::fct()" << endl; }
virtual void fct( int ) { cout << "A::fct( int )" << endl; }
} ;

class B : public A
{
public :
virtual void fct( int ) { cout << "B::fct( int )" << endl; }
// [C++ Avertissement] Main.cpp(40): W8022 'B::fct(int)' cache une
fonction virtuelle 'A::fct()'
};
...

Le fait que la déclaration de fct dans B cache l'accès à fct dans A
s'exprime tout à fait normalement sous la forme d'une erreur de
compilation

(ligne de code et messages du compilateur portés en commentaires sur le
code

ci-dessus). Ce comportement est conforme à la norme (points 3.3.7.3 et
10.2

du Standard).


Je ne comprends pas bien quelle fonction cache quelle autre fonction.
Notemment comment B::fct( int ) peut bien cacher A::fct( ) alors qu'elles
n'ont pas la même signature. Elle ne 'cache' pas non plus A::fct( int ) mais
la redéfinit, ce qui est tout à fait normal vu que cette dernière est
virtuelle.

J'ai l'impression qu'il y a un problème, soit le code que tu as posté n'est
pas celui qui a été compilé, soit tu as bidouillé les options de
compilation. Me trompé-je ?

Je remarque par contre que l'accès à A::fct() n'est pas caché au
compilateur

pour la ligne

pb->fct() ;

qui non seulement compile, mais encore fournit les résultats attendus
(sortie console = "B::fct(int)").


Encore un truc incohérent. Comment fct() peut se traduire par un appel à
fct( int )...

Je suppose qu'en l'occurrence, le problème du masquage des noms est
contourné par le compilateur grâce au recours à la table des méthodes
virtuelles.

Ma question est : pouvez-vous confirmer cette hypothèse ?


Mon hypothèse, c'est qu'il y a quelque chose qui cloche sacrément avec ton
environnement actuel. Recompiles tout, réinitialise les options de
compilation avant, si celà persiste, réinstalle C++ Builder...

Questions subsidiaires :
- ce comportement est-il implémenté dans le Standard (je n'ai pas trouvé
de

référence, mais l'ouvrage est assez gros pour que je puisse y louper des
infos) ?
- si oui, où ?
- comment interagissent la recherche des noms (name lookup) et le
traitement

du polymorphisme lors de la phase de compilation (priorités, résolution
des

conflits, etc... toute info est la bienvenue) ?


Dans le cas des fonctions virtuelles, si tu appelles la fonction via une
référence ou un pointeur, il y a un parcours de la classe correspondant au
type réel de l'objet en remontant vers le haut de la hiérarchie jusqu'à
trouver une définition de la fonction. Si elle est définie dans la classe de
l'objet, c'est cette définition qui est appelée.

Par ailleurs, si deux fonctions ne prennent pas les mêmes paramètres, elles
ne peuvent pas se masquer l'une l'autre. Le seul cas où une fonction va en
masquer une autre, c'est quand deux fonctions (une dans une classe de base,
une autre dans une classe dérivée) ont exactement les mêmes paramètres alors
qu'elle n'est pas déclarée virtuelle (au moins) dans la classe de base.

Chris

Avatar
Christophe Brun
"Christophe Lephay" a écrit dans le message
de news:bfhp2k$ppn$
"Christophe Brun" a écrit dans le message de
news:3f1c4588$0$9626$


Je ne comprends pas bien quelle fonction cache quelle autre fonction.
Notemment comment B::fct( int ) peut bien cacher A::fct( ) alors qu'elles
n'ont pas la même signature. Elle ne 'cache' pas non plus A::fct( int )
mais

la redéfinit, ce qui est tout à fait normal vu que cette dernière est
virtuelle.
J'ai l'impression qu'il y a un problème, soit le code que tu as posté
n'est

pas celui qui a été compilé, soit tu as bidouillé les options de
compilation. Me trompé-je ?



Oui.
B::fct(int) cache les méthode nommées fct au sein de la classe A, quelle que
soit leur signature, en vertu justement des règles de 'name hiding' qui sont
définies les paragraphes du Standard que j'ai cités plus haut. Je confirme
que ce code est correct, que ce comportement est normal, que omn
environnement est sain et que mon compilateur n'a pas été bidouillé ;o)
Pour info, il est possible (et légal) de rendre à nouveau visibloes des
méthodes fct() de la classe A dans la classe A, en utilisant dans la
déclaration de B une directive using.
En fait, ma question porte plus précisément sur le fait que le polymorphisme
semble contourner les règles de 'name hiding', et c'est ce comportement que
je cherche à préciser...

Je remarque par contre que l'accès à A::fct() n'est pas caché au
compilateur

pour la ligne

pb->fct() ;

qui non seulement compile, mais encore fournit les résultats attendus
(sortie console = "B::fct(int)").


Encore un truc incohérent. Comment fct() peut se traduire par un appel à
fct( int )...



Autant pour moi, c'est bien une faute de frappe. C'est "pb->fct( 10 ) "
qu'il faut lire ici.


Par ailleurs, si deux fonctions ne prennent pas les mêmes paramètres,
elles

ne peuvent pas se masquer l'une l'autre. Le seul cas où une fonction va en
masquer une autre, c'est quand deux fonctions (une dans une classe de
base,

une autre dans une classe dérivée) ont exactement les mêmes paramètres
alors

qu'elle n'est pas déclarée virtuelle (au moins) dans la classe de base.



Faux ! Voir règles citées en amont. J'ajouterai que les règles de 'name
hiding' ne se limitent pas aux noms de fonctions. Mais c'est là un autre
sujet...


Avatar
Jean-Marc Bourguet
"Christophe Brun" writes:

Ma question est : pouvez-vous confirmer cette hypothèse ?
Questions subsidiaires :
- ce comportement est-il implémenté dans le Standard (je n'ai pas trouvé de
référence, mais l'ouvrage est assez gros pour que je puisse y louper des
infos) ?


Oui, c'est le comportement requis par la norme.

- si oui, où ?


Dans la partie recherche des noms. On ne cherche dans les classes de
base que si le nom n'a pas ete trouve dans la classe fille.

- comment interagissent la recherche des noms (name lookup) et le
traitement du polymorphisme lors de la phase de compilation
(priorités, résolution des conflits, etc... toute info est la
bienvenue) ?


A partir du nom on trouve d'abord les fonctions candidates puis on
elimine celles qui n'ont pas la bonne signature (ca peut etre toutes),
on regarde si elle est accessible et si elle l'est on regarde si elle
est virtuelle ou pas. Cette recherche se fait avec le type statique
(donc pour tes pointeurs, c'est des A*).

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
Serge Paccalin
Le mardi 22 juillet 2003 à 09:02, Serge Paccalin a écrit dans
fr.comp.lang.c++ :

Mais, pour répondre à Christophe¹, c'est juste une histoire de portée et
un masquage, pas une destruction : il n'y a pas de B::fct(), c'est tout,
mais A::fct() continue à exister.


¹ Ch. Brun, voulais-je dire.

J'ajoute que le paragraphe intéressant de la norme est le 13.2 :

13.2 Declaration matching

1 Two function declarations of the same name refer to the same function
if they are in the same scope and have equivalent parameter
declarations (13.1). A function member of a derived class is not in
the same scope as a function member of the same name in a base class.

[Example:
class B {
public:
int f(int);
};

class D : public B {
public:
int f(char*);
};

Here D::f(char*) hides B::f(int) rather than overloading it.

void h(D* pd)
{
pd­>f(1); // error:
// D::f(char*) hides B::f(int)
pd­>B::f(1); // OK
pd­>f("Ben"); // OK, calls D::f
}

---end example]

--
___________ 2003-07-22 09:13:23
_/ _ _`_`_`_) Serge PACCALIN -- sp ad mailclub.net
_L_) Il faut donc que les hommes commencent
-'(__) par n'être pas fanatiques pour mériter
_/___(_) la tolérance. -- Voltaire, 1763

Avatar
Christophe Lephay
"Christophe Brun" a écrit dans le message de
news:3f1cde5e$0$9624$
B::fct(int) cache les méthode nommées fct au sein de la classe A, quelle
que

soit leur signature, en vertu justement des règles de 'name hiding' qui
sont

définies les paragraphes du Standard que j'ai cités plus haut.


Je n'ai pas accès à la norme. Pourrais-tu faire un petit copier-coller du
paragraphe en question, stp (je suis curieux de voir précisément ce qui y
est dit) ?

Chris

Avatar
Christophe Brun
"Serge Paccalin" a écrit dans le message
de news:
Le mardi 22 juillet 2003 à 09:02, Serge Paccalin a écrit dans
fr.comp.lang.c++ :

J'ajoute que le paragraphe intéressant de la norme est le 13.2 :

13.2 Declaration matching

1 Two function declarations of the same name refer to the same function
if they are in the same scope and have equivalent parameter
declarations (13.1). A function member of a derived class is not in
the same scope as a function member of the same name in a base class.

Salut Serge ! Je note le paragraphe. C'est en effet l'un des points que je

recherchais.
Et pour compléter, sur demande de l'autre Christophe :

3.3.7.3 : "In a member function definition, the declaration of a local name
hides the declaration of a member of the class with the same name; see
3.3.6. The declaration of a member in a derived class (clause 10) hides the
declaration of a member of a base class of the same name; see 10.2."

10.2.2 : "The following steps define the result of name lookup in a class
scope, C. First, every declaration for the name in the class and in each of
its base class subobjects is considered. A member name f in one subobject B
hides a member name f in a subobject A if A is a base class subobject of B.
Any declarations that are so hidden are eliminated from consideration. Each
of these declarations that was introduced by a usingdeclaration is
considered to be from each subobject of C that is of the type containing the
declaration designated by the usingdeclaration. If the resulting set of
declarations are not all from subobjects of the same type, or the set has a
nonstatic member and includes members from distinct subobjects, there is an
ambiguity and the program is illformed. Otherwise that set is the result of
the lookup."

Avatar
Christophe Lephay
"Christophe Brun" a écrit dans le message de
news:3f1d73c9$0$9625$
"Serge Paccalin" a écrit dans le message
de news:
Le mardi 22 juillet 2003 à 09:02, Serge Paccalin a écrit dans
fr.comp.lang.c++ :

J'ajoute que le paragraphe intéressant de la norme est le 13.2 :

13.2 Declaration matching

1 Two function declarations of the same name refer to the same function
if they are in the same scope and have equivalent parameter
declarations (13.1). A function member of a derived class is not in
the same scope as a function member of the same name in a base class.

Salut Serge ! Je note le paragraphe. C'est en effet l'un des points que je

recherchais.
Et pour compléter, sur demande de l'autre Christophe :

3.3.7.3 : "In a member function definition, the declaration of a local
name

hides the declaration of a member of the class with the same name; see
3.3.6. The declaration of a member in a derived class (clause 10) hides
the

declaration of a member of a base class of the same name; see 10.2."


Mais 13.2 dit bien que si les paramètres ne sont pas les mêmes, les noms ne
désignent pas les mêmes fonctions...

Chris


Avatar
Christophe Brun
"Christophe Lephay" a écrit dans le message
de news:bfjt0e$vd$

1 Two function declarations of the same name refer to the same
function



if they are in the same scope and have equivalent parameter
declarations (13.1). A function member of a derived class is not in
the same scope as a function member of the same name in a base
class.







Mais 13.2 dit bien que si les paramètres ne sont pas les mêmes, les noms
ne

désignent pas les mêmes fonctions...

Le point intéressant dans 13.2 est l'allusion à la portée. En l'occurrence,

les méthodes d'une classe dérivée ne sont pas dans la même portée que celles
de la classe de base. C'est justement dans ce cas que se pose le problème du
masquage des noms (et que les autres articles entrent en jeu).



Avatar
Christophe Brun
"Jean-Marc Bourguet" a écrit dans le message de
news:

- comment interagissent la recherche des noms (name lookup) et le
traitement du polymorphisme lors de la phase de compilation
(priorités, résolution des conflits, etc... toute info est la
bienvenue) ?


A partir du nom on trouve d'abord les fonctions candidates puis on
elimine celles qui n'ont pas la bonne signature (ca peut etre toutes),
on regarde si elle est accessible et si elle l'est on regarde si elle
est virtuelle ou pas. Cette recherche se fait avec le type statique
(donc pour tes pointeurs, c'est des A*).

Ha voilà ! La mention du type #statique# est probablement ce qui manque dans

ma reconstruction
Merci pour la précision !
:o)