private, private et private
Le
Fabien LE LEZ
Bonjour,
Dans certaines classes, j'ai trois types de membres privés :
- des membres "réellement" privés, auxquels aucune autre classe n'a
accès ;
- des déclarations de nouvelles fonctions virtuelles (éventuellement
pures) ;
- des implémentations de fonctions virtuelles d'une classe de base.
Exemple :
class B
{
private:
virtual void f()= 0;
};
class D: public B
{
private:
/*virtual*/ void f(); // Fonction qui vient de B.
void g(); // Fonction spécifique à D.
int une_variable_membre;
virtual void h(); // Fonction que les classes héritant de D.
};
J'aimerais savoir comment vous faites pour distinguer visuellement ces
différent types de membres privés.
Mettez-vous trois sections "private:" différentes, toujours dans le
même ordre ?
Y a-t-il d'autres méthodes ?
Question subsidiaire : spécifiez-vous le "virtual" même quand il est
implicite (comme pour B::f()) ?
Merci d'avance
Dans certaines classes, j'ai trois types de membres privés :
- des membres "réellement" privés, auxquels aucune autre classe n'a
accès ;
- des déclarations de nouvelles fonctions virtuelles (éventuellement
pures) ;
- des implémentations de fonctions virtuelles d'une classe de base.
Exemple :
class B
{
private:
virtual void f()= 0;
};
class D: public B
{
private:
/*virtual*/ void f(); // Fonction qui vient de B.
void g(); // Fonction spécifique à D.
int une_variable_membre;
virtual void h(); // Fonction que les classes héritant de D.
};
J'aimerais savoir comment vous faites pour distinguer visuellement ces
différent types de membres privés.
Mettez-vous trois sections "private:" différentes, toujours dans le
même ordre ?
Y a-t-il d'autres méthodes ?
Question subsidiaire : spécifiez-vous le "virtual" même quand il est
implicite (comme pour B::f()) ?
Merci d'avance

Poser une question


Moi, c'est ce que j'aurais tendance à faire.
Je crois qu'il y a différents points de vue. Était-ce Valentin
(quelqu'un sait ce qu'il devient ?) qui disait utiliser cette solution :
class A {
virtual void f();
};
class B : public A {
override void f();
};
avec une définition de override qui pouvait être soit :
#define override
soit
#define override virtual
Le problème est que si l'on met virtuel, on peut rendre virtuel une
fonction qui ne l'était pas et cacher la fonction non virtuelle de
départ. Ne rien mettre, en revanche, demandait de connaître la classe
mère pour savoir si la fonction était ou non virtuelle.
Mettre "override" permettait de signaler qu'on voulait redéfinir une
fonction sans pour autant introduire d'effet de bord.
L'intérêt de changer la définition de rien à virtual permettait aussi de
détecter des erreurs : si le comportement du programme change en
changeant la définition de override, c'est qu'on a fait une erreur sur
la virtualité des fonctions...
J'avais trouvé cela convainquant à l'époque et l'ai adopté pour mon
propre code.
--
Arnaud
Moi aussi. Parfois même plus.
Disons plutôt, qui ne concerne que de l'implémentation. Des
membres pour lesquels la définition Java de private
conviendrait.
Prèsque toujours pûres, d'après mon expérience. (Mais si je me
souviens bien, c'était beaucoup moins vrai quand j'ai fait une
GUI.)
Mais pourquoi insistes-tu sur « nouvelles » ? Dans les classes
dérivées, les supplantations sont aussi privées, et j'aurais
tendance à les voir comme faisant partie de la même catégorie
des « privées ». (Mais c'est juste un point de vue.)
Je ne vois pas ça comme une catégorie distincte de la
précédante. En revanche, j'ai aussi :
-- des declarations faites uniquement pour leurs effets de bord
sur l'interface publique -- la declaration d'un constructeur
de copie ou d'un opérateur d'affectation, surtout, mais
aussi dans certains cas précis, des surcharges des fonctions
publiques, pour empècher certaines conversions implicites
lors de leur appel. (Je crois ne jamais m'être servi de
cette possibilité, mais je sais que la technique existe.)
-- des declarations qui servent à certains amis seulement (par
rapport à celles qui sont réelement privées, et que même les
amis ne doivent pas utiliser).
Grosso modo, c'est ça. Bien que l'ordre n'est pas
rigueureusement fixe ; à part que les membres réelement privés
sont toujours derniers.
Pour les privés utilisés par les amis, j'ajoute un commentaire.
Sinon, c'est assez clair -- si la declaration qui suit private:
est une fonction virtuelle, par exemple, ou si c'est le
constructeur de copie. Ce qui donne :
class C
{
friend class F ;
public:
// ...
private:
virtual void f() = 0 ;
// ...
private:
C( C const& other ) ;
C& operator=( C const& other ) ;
private: // sauf pour F...
// ...
private: // really.
// ...
} ;
Je n'en connais pas, mais je n'en ai pas cherché non plus.
L'idiome des fonctions virtuelles privées et encore plus celui
du constructeur privé sans implémentation sont assez connus pour
qu'ils se passent de commentaires, a mon avis. (Dans le code
unitquement pour moi-même, j'hérite d'une classe
UncopiableObject pour supprimer la copie et l'affectation. Mais
dans le code que les autres doivent aussi comprendre, je préfère
l'idiome classique, immédiatement reconnu, à une astuce à moi,
aussi parlant soit-elle.)
Toujours. Si je sais que la fonction est virtuelle, pourquoi
est-ce que je cacherais le fait de celui qui lit mon code ?
--
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
Oui.
Parce que bien souvent, je n'ai que deux types de fonctions,
complémentaires :
- des fonctions virtuelles pures
- des implémentations, qu'aucune classe dérivée ne change.
Ben... C'est exactement l'inverse.
La catégorie précédente ajoute du boulot pour les classes dérivées ;
cette catégorie en enlève.
Typiquement, j'ai souvent un truc de ce genre :
class B
{
virtual int f (int)= 0;
};
class D: public B
{
virtual int g (int)= 0;
virtual int f (int x) { return 2-g(4*x); }
};
class DD: public D
{
virtual int g (int);
// On laisse f(int) telle quelle, elle convient très bien.
};
Moi, depuis que j'ai découvert l'idiome PIMPL (ici même d'ailleurs), je mets
toutes mes données liées uniquement à l'implémentation dans un pimpl, et
tout le reste en protected. Mais bon, je suis encore novice, donc ce n'est
probablement pas la meilleur chose finalement ...
--
Hamiral
Groumpf ?
Pimpl est un idiome certes très utile, mais relativement lourd, qu'on
ne doit donc utiliser que quand on en a besoin.
Et quand on a des hiérarchies de classes avec des fonctions virtuelles
en veux-tu en voilà, ça risque d'être assez pénible à gérer.
Quant à mettre "tout le reste en protected", j'ai du mal à voir ce que
tu veux dire.
Là encore, "protected" est utile, mais d'utilisation tout de même
assez limitée. Généralement, une section "protected:" contient assez
peu de fonctions (et aucune variable).