OVH Cloud OVH Cloud

"function hiding" en C++

24 réponses
Avatar
Nicolas Castagne
Salutations,

je suis en train de réviser mes bases en C++ et... je ne comprends pas
pourquoi le "standard committee" a mis en place le mécanisme de
"function hiding" dans le langage.

Pourquoi diable si on écrit :
class Base {
void foo( int ) {}
};
class Derived: public Base {
void foo( char const [] ) {}
};
alors la méthode Base::foo(int) est cachée dans la classe fille Derived ?

Pourquoi faut il déclarer "using Base::foo ;" explicitement dans la
classe fille pour avoir de nouveau accès à Base::foo(int) ?


Ce n'est pas la première fois que je me pose la question, mais je n'ai
jamais trouvé de réponse satisfaisante, même après avoir posté sur
différents forums et newsgroup.
En tout cas, ce mécanisme me semble anti-intuitif...

Je serais très reconnaissant à quiconque pourrait me donner une bonne
raison / un bon exemple / un pointeur WWW !

Merci d'avance !
Nicolas

REFERENCES
C++ FAQ LITE / Marshall Cline :
http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9
La FAQ de Cline explique que le mécanisme existe, mais n'explique pas
pourquoi...

Le fil "reason for existance of function hiding" sur un Forum :
http://www.thescripts.com/forum/thread460595.html
Pas de 'bonne raison' donnée ici non plus.

Le fil "Why does "function hiding" exists in C++" des news comp.lang.c++.
Rien de clair là non plus.

10 réponses

1 2 3
Avatar
meow
Merci beaucoup pour m'avoir permis de découvrir cette nouvelle
facétie de C++, je ne connaissais en effet pas encore ce comportement
de "cache-cache"... And I say Argh, au passage.
Pour etre certain d'avoir tout bien compris je me permet une réponse
que je vous invites à corriger et moduler :

Pourquoi faut il déclarer "using Base::foo ;" explicitement dans la
classe fille pour avoir de nouveau accès à Base::foo(int) ?
Après avoir lu les arguments de ce fil de discussion j'aurais tendance

à dire que le fait de cacher les nom de fonctions redéfinis(ce sont
les noms qui sont "redéfinis") est un moyen de se protéger d'une
surcouche d'appels implicites à des fonctions de la classe de base. En
gros, lorsqu'on ecrit Derived et qu'on définit une fonction toto dont
le nom existe dans la classe de base, on veut pouvoir controler tous
les appels à toto.
Dans ce cadre "using Base::toto;" permet de dire au compilo qu'on sait
ce qu'on fait et que s'il voit des appels à un toto(types) non défini
dans Derived c'est normal il peut aller les chercher au dessus plutot
que de se faire des noeuds au processeur par exemple en cherchant à
transtyper pour appeller Derived::toto(autretype)

A ce que j'ai vu, il y a aussi un moyen plus explicite : en indiquant
clairement le scope :
class Base {
void toto( int ) ;
public:
void toto( char* ) ;
} ;
class Derived : public Base {
public:
void toto( double ) ;
void tutu( char* ) { Base::toto(char *); }

} ;


ça va ? J'ai bon ?

Avatar
Jean-Marc Bourguet
"kanze" writes:

Sylvain wrote:
James Kanze wrote on 13/05/2006 11:47:

Mon point reste. Pour les fonctions privées, toute autre
solution serait problamatique. Du coup, l'argument, c'est
l'orthogonalité -- et c'est un argument du poids, à mon
avis,


c'est à dire ? faut-il comprendre que le compilo va avoir
suffisamment de mal à remonter l'arborescense de classes lors
de la recherche d'une méthode à signature (prototype) donnée,
qu'il sera vraiment en peine de traiter, en plus, un modifier
'public' ou 'private' ??


Le compilateur, non. Mais la règle est plus simple à comprendre
s'il n'y a pas de différence entre la gestion des public et des
private.


Moi, ca me semble plus simple a comprendre s'il n'y a pas de
difference entre visibilite et accessibilite. Je suis peut-etre
distrait, mais je ne vois pour le moment pas d'interet dans cette
difference; ca force dans l'ecriture de classes derivee a etre
conscient de choses dont on ne devrait pas s'occuper.

J'ai la faiblesse de penser qu'idealement la partie privee devrait
etre modifiable sans que ca puisse entrainer un changement de
comportement dans le code qui utilise la classe, et meme sans que ca
necessite de recompiler le code qui l'utilise. Ce n'est pas le cas en
C++, et j'ai du mal a voir comment on pourrait implementer
efficacement le deuxieme desiderata de maniere aussi efficace
qu'actuellement en presence de variables automatiques et de
l'arithmetique sur les pointeurs -- pour les variables non
automatiques, recuperer la taille dans une globale aurait
vraissemblablement un cout acceptable pour moi face au temps
generalement pris par l'allocation dynamique.

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
Jean-Marc Bourguet
Sylvain writes:

Jean-Marc Bourguet wrote on 12/05/2006 20:56:
Dans ce que tu as coupé il y avait:

si j'ai bonne mémoire -- il y a un passage là-dessus dans
D&E, mais je n'ai pas le bouquin ici -- une première version
des règles de résolution de surchage aurait posé des
problèmes -- je ne sais plus lesquels -- qu'on a évité
ainsi. Ensuite les règles de résolution de surchage ont été
modifiée, mais on n'est pas revenu sur ce choix. Quand on
s'en est rendu compte, il y avait trop d'existant.
qui réponds plus ou moins à tes deux questions/objections


(du moins qui donne une spéculation basée sur mes souvenirs
de lecture de D&E).


merci Jean-Marc, j'avais bien lu en effet une spéculation. j'ai préféré
retenir les faits ou informations.
JD a confirmé cet ouvrage (sans l'ombre d'un ombre), donc merci pour cette
référence.


C'est une des references quand on cherche a savoir le pourquoi des
choses. L'ARM est une autre.

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
Gabriel Dos Reis
Jean-Marc Bourguet writes:

| "kanze" writes:
|
| > Sylvain wrote:
| > > James Kanze wrote on 13/05/2006 11:47:
| >
| > > > Mon point reste. Pour les fonctions privées, toute autre
| > > > solution serait problamatique. Du coup, l'argument, c'est
| > > > l'orthogonalité -- et c'est un argument du poids, à mon
| > > > avis,
| >
| > > c'est à dire ? faut-il comprendre que le compilo va avoir
| > > suffisamment de mal à remonter l'arborescense de classes lors
| > > de la recherche d'une méthode à signature (prototype) donnée,
| > > qu'il sera vraiment en peine de traiter, en plus, un modifier
| > > 'public' ou 'private' ??
| >
| > Le compilateur, non. Mais la règle est plus simple à comprendre
| > s'il n'y a pas de différence entre la gestion des public et des
| > private.
|
| Moi, ca me semble plus simple a comprendre s'il n'y a pas de
| difference entre visibilite et accessibilite.

hmm, cela me semble un peu surprenant puisque même dans le langage
courant, « accessibilité » != « visibilité ».

| Je suis peut-etre
| distrait, mais je ne vois pour le moment pas d'interet dans cette
| difference; ca force dans l'ecriture de classes derivee a etre
| conscient de choses dont on ne devrait pas s'occuper.

une fonction peut être utile à un conglomerat de classe
uniquement. Dans ce cas, la fonction devrait être accessible à ces
classes et sans leur être invisible.

-- Gaby
Avatar
Jean-Marc Bourguet
Gabriel Dos Reis writes:

| Moi, ca me semble plus simple a comprendre s'il n'y a pas de
| difference entre visibilite et accessibilite.

hmm, cela me semble un peu surprenant puisque même dans le langage
courant, « accessibilité » != « visibilité ».

| Je suis peut-etre distrait, mais je ne vois pour le moment pas
| d'interet dans cette difference; ca force dans l'ecriture de
| classes derivee a etre conscient de choses dont on ne devrait pas
| s'occuper.

une fonction peut être utile à un conglomerat de classe
uniquement. Dans ce cas, la fonction devrait être accessible à ces
classes et sans leur être invisible.


Je me suis peut-etre mal exprime. Je ne vois pas la necessite de
rendre ces concepts orthogonaux dans un langage de programmation. On
peut imaginer que la visibilite implique l'accessibilite et
reciproquement. Ce ne serait plus du C++, nous sommes d'accord. Il y
aurait toujours deux concepts en presence, nous sommes d'accord. Il
n'y aurait qu'un ensemble de regles, ce qui me semble plus simple.

Considerons les deux variables visibilite et accessibilite.

Le cas visible et accessible est utile.

Le cas invisible et inaccessible aussi (meme s'il n'existe pas en C++,
en particulier dans le cadre de la maintenance, ca permet d'ajouter un
membre en etant sur de ne pas impacter le code utilisateur par un
choix malheureux de nom -).

Le cas visible et inaccessible me semble moins utile que le cas
invisible et inaccessible, en particulier je ne vois pas de probleme
qu'il resouds que le second ne resouds pas non plus.

Le cas invisible et accessible me semble tordu (meme si on n'en est
pas loin en C++ avec la supplantation de membres virtuels prives, mais
ce n'est pas exactement la meme chose).

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
Gabriel Dos Reis
Jean-Marc Bourguet writes:

| Gabriel Dos Reis writes:
|
| > | Moi, ca me semble plus simple a comprendre s'il n'y a pas de
| > | difference entre visibilite et accessibilite.
| >
| > hmm, cela me semble un peu surprenant puisque même dans le langage
| > courant, « accessibilité » != « visibilité ».
| >
| > | Je suis peut-etre distrait, mais je ne vois pour le moment pas
| > | d'interet dans cette difference; ca force dans l'ecriture de
| > | classes derivee a etre conscient de choses dont on ne devrait pas
| > | s'occuper.
| >
| > une fonction peut être utile à un conglomerat de classe
| > uniquement. Dans ce cas, la fonction devrait être accessible à ces
| > classes et sans leur être invisible.
|
| Je me suis peut-etre mal exprime. Je ne vois pas la necessite de
| rendre ces concepts orthogonaux dans un langage de programmation. On

c'est ce point qui ne me semble pas évident.

accessible => visible

ou

invisible => inacessible

mais je ne vois pas du tout pourquoi on devarit avoir

accessible <=> accessible


Ces concepts, même dans le langage courant, ne sont pas équivalent. Je
ne suis pas certain du gain obtenu en les rendant équivalents.

| peut imaginer que la visibilite implique l'accessibilite et
| reciproquement. Ce ne serait plus du C++, nous sommes d'accord. Il y

bien sûr ; je parlais de manière un peut plus générale.

| aurait toujours deux concepts en presence, nous sommes d'accord. Il
| n'y aurait qu'un ensemble de regles, ce qui me semble plus simple.
|
| Considerons les deux variables visibilite et accessibilite.
|
| Le cas visible et accessible est utile.
|
| Le cas invisible et inaccessible aussi (meme s'il n'existe pas en C++,
| en particulier dans le cadre de la maintenance, ca permet d'ajouter un
| membre en etant sur de ne pas impacter le code utilisateur par un
| choix malheureux de nom -).
|
| Le cas visible et inaccessible me semble moins utile que le cas
| invisible et inaccessible, en particulier je ne vois pas de probleme
| qu'il resouds que le second ne resouds pas non plus.

L'exemple que j'avais donné dans mon précédent message pointait
justement dans un cas (courant) d'utilisation.

| Le cas invisible et accessible me semble tordu (meme si on n'en est
| pas loin en C++ avec la supplantation de membres virtuels prives, mais
| ce n'est pas exactement la meme chose).

en effet. Je crois que Java est aussi dans cette catégorie là.

-- Gaby
Avatar
kanze
Jean-Marc Bourguet wrote:
Gabriel Dos Reis writes:

| Moi, ca me semble plus simple a comprendre s'il n'y a pas de
| difference entre visibilite et accessibilite.

hmm, cela me semble un peu surprenant puisque même dans le langage
courant, « accessibilité » != « visibilité ».

| Je suis peut-etre distrait, mais je ne vois pour le moment pas
| d'interet dans cette difference; ca force dans l'ecriture de
| classes derivee a etre conscient de choses dont on ne devrait pas
| s'occuper.

une fonction peut être utile à un conglomerat de classe
uniquement. Dans ce cas, la fonction devrait être accessible à ces
classes et sans leur être invisible.


Je me suis peut-etre mal exprime. Je ne vois pas la necessite de
rendre ces concepts orthogonaux dans un langage de programmation. On
peut imaginer que la visibilite implique l'accessibilite et
reciproquement. Ce ne serait plus du C++, nous sommes d'accord. Il y
aurait toujours deux concepts en presence, nous sommes d'accord. Il
n'y aurait qu'un ensemble de regles, ce qui me semble plus simple.

Considerons les deux variables visibilite et accessibilite.

Le cas visible et accessible est utile.


En général, oui, si on veut se servir de la classe.

Le cas invisible et inaccessible aussi (meme s'il n'existe pas en C++,
en particulier dans le cadre de la maintenance, ca permet d'ajouter un
membre en etant sur de ne pas impacter le code utilisateur par un
choix malheureux de nom -).


Je suis d'accord, même si c'est un concepte qu'on ne sait pas
exprimé en C++.

Le cas visible et inaccessible me semble moins utile que le cas
invisible et inaccessible, en particulier je ne vois pas de probleme
qu'il resouds que le second ne resouds pas non plus.


C'est le cas des fonctions virtuelles privées, par exemple. Tu
ne peux pas appelé la fonction, mais tu peux bien la supplanter.

Je crois aussi qu'une partie du problème se tourne autour de ce
qu'on entend par la visibilité. Un constructeur de copie privé
ferait bien partie de la cas invisible et inaccessible, sauf
qu'il a l'effet bien visible d'inhiber la génération du
constructeur de copie par défaut. Je ne suis pas sûr où le
mettre dans tes catégorisations.

Le cas invisible et accessible me semble tordu (meme si on
n'en est pas loin en C++ avec la supplantation de membres
virtuels prives, mais ce n'est pas exactement la meme chose).


En effet.

Strictement parlant, évidemment, il n'y a pas de catégorie avec
invisible en C++; quand tu parles d'invisible et inaccessible,
tu parles de ce que tu veux, non de ce que tu as. Mais j'ai du
mal à voir comment tu catégorises les virtuelles privées ici --
peut-être je suis en train de me laisser trop conditionner par
Java, mais une fonction invisible virtuelle n'a pas de sens ; tu
ne peux pas la supplanter, parce que si le nom est invisible, le
compilateur doit prendre tes essaies de supplantage comme la
déclaration d'une fonction nouvelle (elle aussi virtuelle).
Donc, par exemple, en Java :

class Base
{
private void f() ;
}

class Derived extends Base
{
public void f() ;
} ;

le f() dans Derived ne supplante pas le f() dans Base -- tout se
passe comme si le f() dans Base n'existait pas.

Je ne suis pas contre une telle catégorie ; elle serait utile
aussi. Mais la catégorie réele de private aujourd'hui -- visible
mais inaccessible -- n'est pas sans intérêt, et m'a bien manqué
quand j'ai fait du Java.

En ce qui concerne la notion de visible/invisible, je ne le
trouve pas très intéressant qu'elle s'applique au niveau protégé
ou d'autres : invisible n'est visible qu'à l'intérieur de la
classe, et visible est visible partout ailleurs.

(Il y a un autre aspect qu'on néglige ici. En C++ et en Java, la
visibilité/accessibilité s'applique au niveau de la classe. Or,
il y a bien eu des fois où je l'aurais voulu au niveau de
l'objet -- qu'une fonction member n'ait pas le droit d'accéder à
certaines parties d'autres objets, même s'ils étaient du même
type.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
Gabriel Dos Reis
"kanze" writes:


[...]

| tu parles de ce que tu veux, non de ce que tu as. Mais j'ai du
| mal à voir comment tu catégorises les virtuelles privées ici --
| peut-être je suis en train de me laisser trop conditionner par
| Java, mais une fonction invisible virtuelle n'a pas de sens ; tu
| ne peux pas la supplanter, parce que si le nom est invisible, le
| compilateur doit prendre tes essaies de supplantage comme la
| déclaration d'une fonction nouvelle (elle aussi virtuelle).

Hmm.

struct Base {
private:
virtual void f() = 0;
};

struct Derived : Base {
void f(int) { }
};

Derived a -- ou plutôt herite -- une fonction virtuelle. Mais elle
est invisible dans Derived.

-- Gaby
Avatar
Jean-Marc Bourguet
Gabriel Dos Reis writes:

Jean-Marc Bourguet writes:

| Gabriel Dos Reis writes:
|
| > | Je suis peut-etre distrait, mais je ne vois pour le moment pas
| > | d'interet dans cette difference; ca force dans l'ecriture de
| > | classes derivee a etre conscient de choses dont on ne devrait pas
| > | s'occuper.
| >
| > une fonction peut être utile à un conglomerat de classe
| > uniquement. Dans ce cas, la fonction devrait être accessible à ces
| > classes et sans leur être invisible.
[...]

| Le cas visible et inaccessible me semble moins utile que le cas
| invisible et inaccessible, en particulier je ne vois pas de probleme
| qu'il resouds que le second ne resouds pas non plus.

L'exemple que j'avais donné dans mon précédent message pointait
justement dans un cas (courant) d'utilisation.


Si c'est ce que j'ai laisse, tu me sembles plaider pour visible et
accessible.

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
Jean-Marc Bourguet
"kanze" writes:

Jean-Marc Bourguet wrote:

Le cas visible et inaccessible me semble moins utile que le cas
invisible et inaccessible, en particulier je ne vois pas de
probleme qu'il resouds que le second ne resouds pas non plus.


C'est le cas des fonctions virtuelles privées, par exemple.


C'est le cas de tout ce qui est prive mais non cache par une autre
definition.

Tu ne peux pas appelé la fonction, mais tu peux bien la supplanter.

Je crois aussi qu'une partie du problème se tourne autour de ce
qu'on entend par la visibilité. Un constructeur de copie privé
ferait bien partie de la cas invisible et inaccessible, sauf
qu'il a l'effet bien visible d'inhiber la génération du
constructeur de copie par défaut. Je ne suis pas sûr où le
mettre dans tes catégorisations.


C'est bien un cas ou visible et inaccessible est utile en C++. Mais
j'ai toujours eu l'impression que c'est un hack, utile mais un hack
tout de meme.

Strictement parlant, évidemment, il n'y a pas de catégorie avec
invisible en C++;


Il y a le cas ou des definitions sont cachees par d'autres dans un
scope imbrique.

quand tu parles d'invisible et inaccessible, tu parles de ce que tu
veux, non de ce que tu as.


Exact.

Mais j'ai du mal à voir comment tu catégorises les virtuelles
privées ici -- peut-être je suis en train de me laisser trop
conditionner par Java, mais une fonction invisible virtuelle n'a pas
de sens ; tu ne peux pas la supplanter, parce que si le nom est
invisible, le compilateur doit prendre tes essaies de supplantage
comme la déclaration d'une fonction nouvelle (elle aussi virtuelle).
Donc, par exemple, en Java :

class Base
{
private void f() ;
}

class Derived extends Base
{
public void f() ;
} ;

le f() dans Derived ne supplante pas le f() dans Base -- tout se
passe comme si le f() dans Base n'existait pas.

Je ne suis pas contre une telle catégorie ; elle serait utile
aussi. Mais la catégorie réele de private aujourd'hui -- visible
mais inaccessible -- n'est pas sans intérêt, et m'a bien manqué
quand j'ai fait du Java.


Tu peux donner un exemple autre que le constructeur de copie?


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


1 2 3