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.

4 réponses

1 2 3
Avatar
kanze
Gabriel Dos Reis wrote:
"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.


Oui et non. On pourrait dire qu'elle n'est pas complétement
invisible, en ce qu'elle a un effet de bord très visible : elle
rend la classe Derived abstraite. Je dirais aussi qu'elle n'est
pas invisible, dans le sens que si on régardait où elle se
trouve, on le verrait. Quand on est dans Derived, c'est qu'on
n'y régarde pas, plutôt qu'elle est invisible.

Mais j'avoue que c'est une question de langage. Qu'est-ce qu'il
faut pour considérer qu'une fonction est « visible » ? À qui (le
compilateur, ou celui qui lit le code) ? Dans le cas de C++, il
y a moins d'ambiguïté, parce qu'on parle d'accessabilité, et non
de visibilité, et d'un certain côté, accessabilité est pûrement
technique. Dans le cas de visibilité, en revanche, on a d'une
côté la signification technique : est-ce que la recherche du nom
va le trouver ?, et de l'autre, une signification plus floue :
est-ce que moi, en tant que programmeur, voit qu'elle est là ?
Est-ce que sa présence ait des effets « visibles » ?

En Java, par exemple, les déclarations privées sont bien
invisibles. Par définition -- en dehors de la classe même, tout
se passe comme si elles n'étaient pas là. C'est un autre point
de vue. Si on se limite à l'alternance public/privé, il y a même
de forts arguments en faveur de ce point de vue, et il n'est pas
sans intérêt de pouvoir déclarer des symboles réelement
invisible en dehors de la classe. Si je voulais ajouter ce
concepte à C++, je crois que j'utiliserais un nouveau mot clé,
disons hidden, qui opèrerait comme un spécification d'accès,
pour arriver à quelque chose comme :

visibilité accès

public public public
protected public protected
private public private
hidden private private

Je trouve que les contrôles d'accès, tels qu'ils marchent
aujourd'hui en C++, sont aussi d'une grande utilité, et
puisqu'on les a, je n'aimerais pas du tout les voir disparaître
(indépendamment de ce que ça ferait à la compatibilité avec le
code existant).

Mais je ne vais pas en proposer quelque chose du genre. Ça
apporte un plus, c'est sûr, mais est-ce que le plus est
suffisant pour valoir ajouter encore au langage -- qui n'est pas
exactement petit, déjà ? Je n'en suis pas convaincu.

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


Dans le cas de la déclaration privée du constructeur de copie
(ou de l'opérateur d'affectation), c'est bien un hack -- il n'y
a rien à dire.

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.


C'est une question de langage. Pour moi, quand on dit
« invisible », ça veut dire qu'on ne peut pas voir la chose,
point à la ligne ; non qu'on n'y régarde pas. Une déclaration
privée en Java est invisible -- quoique tu fasses, en dehors de
la classe, tu n'arrives pas à la voir, ni même en voir des
effets de sa présence.

(Ce n'est pas tout à fait vrai, puisqu'elle joue toujours soit
sur la taille des objets, soit sur la taille du programme. Une
déclaration d'un membre donnée de plus, par exemple, signifie
que tu peux allouer moins d'objet de ce type avant d'épuiser la
mémoire, ou que la localité de ton programme est moins bonne, et
donc, qu'il s'exécute moins vite. Mais bon, nous avons
l'habitude, je crois, de faire abstraction de ces aspects-là.)

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?


Les fonctions virtuelle privée, utilisées soit pour la
programmation par contrat, soit pour le modèle de conception
template.

Aussi : tu peux t'en servir pour inhiber certaines conversions
inplicites lors de l'appel d'une fonction publique. Considère un
instant la légalité et la signification aujourd'hui de :

std::string s ;
double d = 3.14159 ;
s += d ;

Maintenant, supposons qu'on ajoutait à std::string une fonction
privée operator+=( int ). Ne serait-ce pas une amélioration ?

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

Jean-Marc Bourguet wrote:
"kanze" writes:
Jean-Marc Bourguet wrote:
[...]



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.


Dans le cas de la déclaration privée du constructeur de copie
(ou de l'opérateur d'affectation), c'est bien un hack -- il n'y
a rien à dire.
[...]

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?


Les fonctions virtuelle privée, utilisées soit pour la programmation
par contrat, soit pour le modèle de conception template.


En quoi avoir ces fonctions privees plutot que protected apporte
quelque chose?

Si elles ont un comportement utile, pourquoi priver les descendants de
la possibilite d'ajouter a ce comportement sans le reecrire?

Si elles n'ont pas de comportement utile, elles devraient etre
virtuelles pures sans implementation.

Aussi : tu peux t'en servir pour inhiber certaines conversions
inplicites lors de l'appel d'une fonction publique.


Nous sommes dans le meme cadre que la declaration privee du
constructeur de copie. Desactiver quelque chose qu'on a d'office sans
l'avoir demande.

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

Jean-Marc Bourguet wrote:
"kanze" writes:
Jean-Marc Bourguet wrote:
[...]



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.


Dans le cas de la déclaration privée du constructeur de copie
(ou de l'opérateur d'affectation), c'est bien un hack -- il n'y
a rien à dire.
[...]

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?


Les fonctions virtuelle privée, utilisées soit pour la
programmation par contrat, soit pour le modèle de conception
template.


En quoi avoir ces fonctions privees plutot que protected apporte
quelque chose?

Si elles ont un comportement utile, pourquoi priver les
descendants de la possibilite d'ajouter a ce comportement sans
le reecrire?

Si elles n'ont pas de comportement utile, elles devraient etre
virtuelles pures sans implementation.


Elles sont, typiquement, virtuelles pures, sans implémentation.
Par rapport aux fonctions publiques, elles contournent la
validation du contrat. Et l'intérêt qu'elles soient privées,
évidemment, c'est qu'elles ne peuvent pas être appelées par une
classe dérivée. En ce qui concerne l'objet même, évidemment,
c'est sans intérêt, parce que la fonction implémentrice se
trouve dans la classe dérivée, et peut donc être appelée sans
problème. Mais le contrôle d'accès en C++ fonctionne au niveau
de la classe, non au niveau de l'objet -- et on veut bien
empêcher les appels depuis un autre objet. (Maintenant que j'y
pense, protected ferait aussi peut-être l'affaire, parce qu'un
Derived ne peut pas appeler des fonctions protected à travers un
Base*. Mais c'est un peu subtile -- je trouve que private dit
plus clairement ce que je veux.)

Aussi : tu peux t'en servir pour inhiber certaines
conversions inplicites lors de l'appel d'une fonction
publique.


Nous sommes dans le meme cadre que la declaration privee du
constructeur de copie. Desactiver quelque chose qu'on a
d'office sans l'avoir demande.


Tout à fait. Et on pourrait aussi arguer que c'est un hack, pour
contourner un défaut du langage -- logiquement, il ne doit pas y
avoir des conversions implicites d'un double en char. (Je le
ressens légèrement différent, en ce qu'ici on n'a pas empêcher
la génération de quoique ce soit -- les conversions sont
toujours là. Mais le but final est effectivement le même --
empêcher à l'utilisateur l'accès à une fonctionnalité qu'on ne
veut pas fournir.)

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




1 2 3