GNT sans publicité, site mobile, fonctionnalitées exclusives...

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
Lire les 23 réponses

Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 5
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Arnaud Meurgues
Le #281836
Fabien LE LEZ wrote:

Mettez-vous trois sections "private:" différentes, toujours dans le
même ordre ?


Moi, c'est ce que j'aurais tendance à faire.

Question subsidiaire : spécifiez-vous le "virtual" même quand il est
implicite (comme pour B::f()) ?


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

kanze
Le #281835
Fabien LE LEZ wrote:

Dans certaines classes, j'ai trois types de membres privés :


Moi aussi. Parfois même plus.

- des membres "réellement" privés, auxquels aucune autre classe n'a
accès ;


Disons plutôt, qui ne concerne que de l'implémentation. Des
membres pour lesquels la définition Java de private
conviendrait.

- des déclarations de nouvelles fonctions virtuelles (éventuellement
pures) ;


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

- des implémentations de fonctions virtuelles d'une classe de base.


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

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 ?


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.
// ...
} ;

Y a-t-il d'autres méthodes ?


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

Question subsidiaire : spécifiez-vous le "virtual" même quand
il est implicite (comme pour B::f()) ?


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

Fabien LE LEZ
Le #281810
On 28 Apr 2006 00:24:29 -0700, "kanze"
Prèsque toujours pûres, d'après mon expérience.
[...]


Oui.

Mais pourquoi insistes-tu sur « nouvelles » ?


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.

- des implémentations de fonctions virtuelles d'une classe de base.


Je ne vois pas ça comme une catégorie distincte de la
précédante.


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.
};


Hamiral
Le #281766
Fabien LE LEZ wrote:

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.



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

Fabien LE LEZ
Le #281763
On Fri, 28 Apr 2006 21:21:09 +0200, Hamiral
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.


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

Publicité
Suivre les réponses
Poster une réponse
Anonyme