OVH Cloud OVH Cloud

Forme canonique de Coplien et poymorphisme

137 réponses
Avatar
Y a n n R e n a r d
Bonjour à tous,

tout d'abord, merci à tous pour ce newsgroup très instructif, c'est la
première fois que je poste, alors je vais essayer de ne pas me faire
incendier par Fabien ;) :p

Voila mon problème : j'ai un client qui souhaite que toutes les classes
définies dans le projet sur lequel je travaille soient sous la forme
canonique de Coplien (pour ceux qui ne connaissent pas : constructeur
par défaut, constructeur par copie, operateur d'affectation et
destructeur virtuel ou non). Pour que ce soit plus clean (selon eux), le
client demande que toutes les classes dérivent d'une classe de base...
Sauf que je ne vois pas du tout l'intéret de faire ca car je ne vois pas
en quoi ca force à respecter la forme canonique de Coplien.

Concernant l'operateur d'affectation, si je le met virtuel (est ce
quelque chose de propre ?!) comment puis je faire en sorte que les
classes filles utilisent un opérateur correct ? cast dynamique ?

Concernant l'operateur de recopie, là, je vois pas du tout du tout du
tout :)

Bref, je comprends pas du tout cette demande, si quelqu'un pense que
c'est raisonable ou explicable, je veux bien une précision sur l'utilité...

Pour terminer, il faut aussi déporter le code du constructeur et du
destructeur dans une fonction séparée, et là, je comprends plus du
tout... genre quelque chose comme ca :

T::T(void)
{
construct();
}

T::~T(void)
{
destruct();
}

void T::construct(void)
{
// ...
}

void T::destruct(void)
{
// ...
}

Voila voila, votre avis est le bienvenu :)
Merci d'avance,

Yann Renard

10 réponses

1 2 3 4 5
Avatar
Jean-Marc Bourguet
Y a n n R e n a r d
writes:

Voila mon problème : j'ai un client qui souhaite que toutes les
classes définies dans le projet sur lequel je travaille soient sous
la forme canonique de Coplien (pour ceux qui ne connaissent pas :
constructeur par défaut, constructeur par copie, operateur
d'affectation et destructeur virtuel ou non).


La plus part de mes classes ont un constructeur de copie et un
operateur d'affectation prives et non implementes car ces operations
n'ont pas de sens.

Pour que ce soit plus clean (selon eux), le client demande que
toutes les classes dérivent d'une classe de base... Sauf que je ne
vois pas du tout l'intéret de faire ca car je ne vois pas en quoi ca
force à respecter la forme canonique de Coplien.

Concernant l'operateur d'affectation, si je le met virtuel (est ce quelque
chose de propre ?!)


Une semantique de valeur (ou la copie et l'affectation on du sens) est
generalement peu compatible avec des membres virtuels.

comment puis je faire en sorte que les classes filles utilisent un
opérateur correct ? cast dynamique ?

Concernant l'operateur de recopie, là, je vois pas du tout du tout du tout
:)


Le constructeur je suppose. Je vois pas plus que toi.

Bref, je comprends pas du tout cette demande, si quelqu'un pense que c'est
raisonable ou explicable, je veux bien une précision sur l'utilité...


Je ne vois pas de bonnes raisons.

Pour terminer, il faut aussi déporter le code du constructeur et du
destructeur dans une fonction séparée, et là, je comprends plus du
tout... genre quelque chose comme ca :


Je ne comprends pas plus que toi. Faut demander au client.
Attention que pendant l'execution du constructeur et du destructeur,
le type dynamique n'est pas le plus derive. Autrement dit "les
virtuelles ne marchent pas".

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
Laurent Deniau
Jean-Marc Bourguet wrote:
Je ne comprends pas plus que toi. Faut demander au client.
Attention que pendant l'execution du constructeur et du destructeur,
le type dynamique n'est pas le plus derive. Autrement dit "les
virtuelles ne marchent pas".


Je ne comprends pas ce que tu veux dire. D'apres ce que je sais (C++98)

- Les constructeurs ne peuvent pas etre virtuels, donc forcement dans
B::B(), this est de type B*. Et on ne peut pas appeler de methode
virtuelle dans le constructeur. Pour faire des "factory" on fait
l'inverse, une methode virtuelle appelle le constructeur.

- un destructeur virtuel n'est pas different d'une autre methode
virtuelle sur ce point. Dans virtual B::~B(), this peut etre de type D*
ou D derive de B et on peut le retrouver avec un dynamic_cast<>().

Peux-tu m'eclairer sur tes propos?

a+, ld.

Avatar
Laurent Deniau
Y a n n R e n a r d wrote:
Bonjour à tous,

Voila mon problème : j'ai un client qui souhaite que toutes les classes
définies dans le projet sur lequel je travaille soient sous la forme
canonique de Coplien (pour ceux qui ne connaissent pas : constructeur
par défaut, constructeur par copie, operateur d'affectation et
destructeur virtuel ou non). Pour que ce soit plus clean (selon eux), le
client demande que toutes les classes dérivent d'une classe de base...
Sauf que je ne vois pas du tout l'intéret de faire ca car je ne vois pas
en quoi ca force à respecter la forme canonique de Coplien.

Concernant l'operateur d'affectation, si je le met virtuel (est ce
quelque chose de propre ?!) comment puis je faire en sorte que les
classes filles utilisent un opérateur correct ? cast dynamique ?

Concernant l'operateur de recopie, là, je vois pas du tout du tout du
tout :)

Bref, je comprends pas du tout cette demande, si quelqu'un pense que
c'est raisonable ou explicable, je veux bien une précision sur l'utilité...


Je trouve ca effectivement tres interessant et rare de la part d'un
client qui doit deja etre experimente dans la gestion de gros *projet
C++* (d'autre langage OO n'ont pas ces problemes).

Ton client a probalement une vision long terme du projet avec un soucis
de qualite dans l'evolutivite. L'ultra-performance n'est pas sa
priorite. Il vise probablement une progammation differentielle par
contrat, c'est-a-dire que chaque classe de la hierachie fait un peu du
travail puis delegue le reste a sa classe de base. Le virtual permet de
sauter des etapes dans la hierarchie (par ex si un niveau de classe n'a
rien a ajouter ca passe directement a sa classe de base). Les contrats
permettent de verifier qu'a chaque niveau on est bien de le domaine
attendu en entree et en sortie.

Je dirais que c'est tres contraignant sur des petits programmes ou on a
une vue d'ensemble des le depart et que l'evolutivite n'est pas la
priorite. Sur un grand projet, les demandes de ton client sont tres sensees.

Pour terminer, il faut aussi déporter le code du constructeur et du
destructeur dans une fonction séparée, et là, je comprends plus du
tout... genre quelque chose comme ca :

T::T(void)
{
construct();
}


Ca c'est l'inverse des factory.

Je pense que c'est pour du debug (trace, check, message de log) si
construct est virtuelle.

T::~T(void)
{
destruct();
}


idem si destruct est virtuelle.

void T::construct(void)
{
// ...
}

void T::destruct(void)
{
// ...
}


est-ce que dans la classe de base elle ne sont pas declaree virtuelles?

Voila voila, votre avis est le bienvenu :)
Merci d'avance,


J'espere t'avoir aider.

a+, ld.

Avatar
Arnaud Meurgues
Y a n n R e n a r d wrote:

Voila mon problème : j'ai un client qui souhaite que toutes les classes
définies dans le projet sur lequel je travaille soient sous la forme
canonique de Coplien (pour ceux qui ne connaissent pas : constructeur
par défaut, constructeur par copie, operateur d'affectation et
destructeur virtuel ou non).


Ça, c'est un problème, un client qui a des exigences qu'il n'est pas
capable de justifier.

Pour que ce soit plus clean (selon eux), le
client demande que toutes les classes dérivent d'une classe de base...


Et paf ! Un destructeur virtuel sur toutes les classes. Quel drôle
d'idée. Le client ne viendrait pas du Java, par hasard ?

Sauf que je ne vois pas du tout l'intéret de faire ca car je ne vois pas
en quoi ca force à respecter la forme canonique de Coplien.


Ça n'aide en rien. Ça force le destructeur à être virtuel, c'est tout,
et donc toute classe à payer le prix d'une vtable.

Juste par acquis de conscience, quand le client parle de forme de
Coplien, il ne parle pas de ça :
http://c2.com/cgi/wiki?CoplienForm
?

Je n'ai pas lu le bouquin de Coplien. Mais en cherchant sur Google, je
vois des choses bizarres. Sur :
http://cpptips.hyperformix.com/cpptips/orth_can_class
je lis :

«
Also, if you can't define these four member functions so they make
sense, it usually means you're conceptualizing your objects' store wrong.
»

C'est quoi le sens d'un constructeur de copie ou l'affectation pour une
socket ou pour un lock ? Je ne vois pas quel sens je pourrais leur
donner. Cela veut-il dire qu'on ne peut considérer une socket ou un lock
comme des classes ?

Quelles sont les raisons de Coplien pour imposer que ces fonctions
soient systématiquement définies ? N'est-ce pas plutôt pour être certain
qu'on ne sera pas surpris par les versions générées automatiquement par
le compilateur ? Auquel cas, déclarer le constructeur de copie ou
l'assignation comme privés et ne pas les définir, n'est-ce pas aussi une
manière de respecter la forme canonique orthodoxe de Coplien ?

Finalement, le but n'est-il pas de se poser pour chaque classe la
question de savoir ce que doivent faire ces fonctions et si elles sont
pertinentes ? Auquel cas, devoir les déclarer systématiquement pourrait
avoir un avantage. Mais déclarer n'est pas définir. Si une fonction n'a
pas de sens, il faut pouvoir le dire.

Bref, je comprends pas du tout cette demande, si quelqu'un pense que
c'est raisonable ou explicable, je veux bien une précision sur l'utilité...


Il faudrait lire Coplien pour connaître ses arguments. Moi, je ne vois
que ce que j'ai dit juste au-dessus, mais ça ne nécessite pas que ces
fonctions soient systématiquement définis. Juste qu'on se pose
systématiquement la question de leur sémantique.

Pour terminer, il faut aussi déporter le code du constructeur et du
destructeur dans une fonction séparée, et là, je comprends plus du
tout... genre quelque chose comme ca :

T::T(void)
{
construct();
}


Pour le constructeur, ils peuvent vouloir facilement ajouter un
constructeur et du coup, factoriser le code commun des constructeurs.
Sinon, effectivement, je ne vois vraiment pas l'intérêt.

T::~T(void)
{
destruct();
}


Pour les destructeurs, je sèche complètement.

Voila voila, votre avis est le bienvenu :)


Mauvais client. Changer de client. ;-)

--
Arnaud
(Supprimez les geneurs pour me répondre)

Avatar
Jean-Marc Bourguet
Laurent Deniau writes:

Jean-Marc Bourguet wrote:
Je ne comprends pas plus que toi. Faut demander au client.
Attention que pendant l'execution du constructeur et du destructeur,
le type dynamique n'est pas le plus derive. Autrement dit "les
virtuelles ne marchent pas".


Je ne comprends pas ce que tu veux dire. D'apres ce que je sais (C++98)



- Les constructeurs ne peuvent pas etre virtuels, donc forcement
dans B::B(), this est de type B*. Et on ne peut pas appeler de
methode virtuelle dans le constructeur.


Si on peut appeler des membres virtuels. Mais leur resolution n'est
pas celle a laquelle certains (en particulier ceux qui ont fait du
Java) s'attende.

Pour faire des "factory" on fait l'inverse, une methode virtuelle
appelle le constructeur.

- un destructeur virtuel n'est pas different d'une autre methode
virtuelle sur ce point. Dans virtual B::~B(), this peut etre de type
D* ou D derive de B et on peut le retrouver avec un
dynamic_cast<>().


Non.

Peux-tu m'eclairer sur tes propos?


Pendant l'execution du constructeur et du destructeur, l'objet est du
type de la classe construite (et non de la classe la plus derivee).

Appeler un membre virtuel sur this a un comportement defini: la
fonction sera celle de la classe construite ou de l'ancetre la
fournissant (donc c'est un probleme si elle est pure).

Appeler un membre virtuel a travers d'un alias de this qui n'est pas
du type construit ou d'un de ses descendants est indefini.

Les references:

12.7/3 Member functions, including virtual functions (10.3), can be
called during construction or destruction (12.6.2). When a virtual
function is called directly or indirectly from a constructor
(including from the mem-initializer for a data member) or from a
destructor, and the object to which the call applies is the object
under construction or destruction, the function called is the one
defined in the constructor or destructor's own class or in one of its
bases, but not a function overriding it in a class derived from the
constructor or destructor's class, or overriding it in one of the
other base classes of the most derived object (1.8). If the virtual
function call uses an explicit class member access (5.2.5) and the
object-expression refers to the object under construction or
destruction but its type is neither the constructor or destructor's
own class or one of its bases, the result of the call is undefined.

12.7/4 The typeid operator (5.2.8) can be used during construction or
destruction (12.6.2). When typeid is used in a constructor (including
from the mem-initializer for a data member) or in a destructor, or
used in a function called (directly or indirectly) from a constructor
or destructor, if the operand of typeid refers to the object under
construction or destruction, typeid yields the type_info representing
the constructor or destructor's class. If the operand of typeid
refers to the object under construction or destruction and the static
type of the operand is neither the constructor or destructor's class
nor one of its bases, the result of typeid is undefined.

12.7/5 Dynamic_casts (5.2.7) can be used during construction or
destruction (12.6.2). When a dynamic_cast is used in a constructor
(including from the mem-initializer for a data member) or in a
destructor, or used in a function called (directly or indirectly) from
a constructor or destructor, if the operand of the dynamic_cast refers
to the object under construction or destruction, this object is
consid- ered to be a most derived object that has the type of the
constructor or destructor's class. If the operand of the dynamic_cast
refers to the object under construction or destruction and the static
type of the operand is not a pointer to or object of the constructor
or destructor's own class or one of its bases, the dynamic_cast
results in undefined behavior.

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
Laurent Deniau writes:

Y a n n R e n a r d wrote:
Bonjour à tous,
Voila mon problème : j'ai un client qui souhaite que toutes les classes
définies dans le projet sur lequel je travaille soient sous la forme
canonique de Coplien (pour ceux qui ne connaissent pas : constructeur par
défaut, constructeur par copie, operateur d'affectation et destructeur
virtuel ou non). Pour que ce soit plus clean (selon eux), le client
demande que toutes les classes dérivent d'une classe de base... Sauf que
je ne vois pas du tout l'intéret de faire ca car je ne vois pas en quoi
ca force à respecter la forme canonique de Coplien.
Concernant l'operateur d'affectation, si je le met virtuel (est ce
quelque chose de propre ?!) comment puis je faire en sorte que les
classes filles utilisent un opérateur correct ? cast dynamique ?
Concernant l'operateur de recopie, là, je vois pas du tout du tout du
tout :)
Bref, je comprends pas du tout cette demande, si quelqu'un pense que
c'est raisonable ou explicable, je veux bien une précision sur
l'utilité...


Je trouve ca effectivement tres interessant et rare de la part d'un
client qui doit deja etre experimente dans la gestion de gros
*projet C++* (d'autre langage OO n'ont pas ces problemes).


Que demande t'il?

- que toutes les classes soient avec
* constructeur par defaut, desole j'ai des classes qui n'en
ont pas et je ne vois aucune raison d'en imposer un
artificiel
* destructeur: ce n'est pas possible de faire autrement
* assignement et constructeur de copie: je perds mon temps
a les desactiver dans au moins la moitie de mes classes
- que toutes les classes derivent d'une classe de base
* c'est impraticable (comment on fait pour imposer la classe
de base de std::vector, de classes derivees a partir
d'elements d'une bibliotheque tierce ?)
* si c'est pour imposer la forme canonique je ne vois pas
comment faire (tiens sauf pour qqch du genre NotCopiable...
mais avec une telle classe de base, definir l'assignement
et le constructeur de copie, c'est de la perversite)
* ca me fait plutot penser a quelqu'un qui a de l'experience
d'un autre langage ou cette classe de base est presente
d'office que du C++ (tiens bizarrement c'etait la mode au
debut du C++ quand pour une partie des gens OO signifiait
SmallTalk)
- de faire faire le travail des constructeurs et destructeurs par
une autre fonction, pourquoi?

Ton client a probalement une vision long terme du projet avec un
soucis de qualite dans l'evolutivite. L'ultra-performance n'est pas
sa priorite. Il vise probablement une progammation differentielle
par contrat, c'est-a-dire que chaque classe de la hierachie fait un
peu du travail puis delegue le reste a sa classe de base. Le virtual
permet de sauter des etapes dans la hierarchie (par ex si un niveau
de classe n'a rien a ajouter ca passe directement a sa classe de
base). Les contrats permettent de verifier qu'a chaque niveau on est
bien de le domaine attendu en entree et en sortie.

Je dirais que c'est tres contraignant sur des petits programmes ou
on a une vue d'ensemble des le depart et que l'evolutivite n'est pas
la priorite. Sur un grand projet, les demandes de ton client sont
tres sensees.


Je ne vois guere de sens. Il me semble pourtant que j'ai l'experience
de gros projets.

Pour terminer, il faut aussi déporter le code du constructeur et du
destructeur dans une fonction séparée, et là, je comprends plus du
tout... genre quelque chose comme ca :
T::T(void)
{
construct();
}


Ca c'est l'inverse des factory.

Je pense que c'est pour du debug (trace, check, message de log) si
construct est virtuelle.


Expliques-toi, je ne vois pas l'utilite de faire ca systematiquement,
meme avec un objectif d'instrumentation.

T::~T(void)
{
destruct();
}


idem si destruct est virtuelle.


A nouveau je ne vois pas l'utilite.

void T::construct(void)
{
// ...
}

void T::destruct(void)
{
// ...
}


est-ce que dans la classe de base elle ne sont pas declaree virtuelles?


Qu'est-ce que ca change?

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
Laurent Deniau
Jean-Marc Bourguet wrote:
Laurent Deniau writes:


Jean-Marc Bourguet wrote:

Je ne comprends pas plus que toi. Faut demander au client.
Attention que pendant l'execution du constructeur et du destructeur,
le type dynamique n'est pas le plus derive. Autrement dit "les
virtuelles ne marchent pas".


Je ne comprends pas ce que tu veux dire. D'apres ce que je sais (C++98)

- Les constructeurs ne peuvent pas etre virtuels, donc forcement
dans B::B(), this est de type B*. Et on ne peut pas appeler de
methode virtuelle dans le constructeur.


Si on peut appeler des membres virtuels. Mais leur resolution n'est
pas celle a laquelle certains (en particulier ceux qui ont fait du
Java) s'attende.


Pour faire des "factory" on fait l'inverse, une methode virtuelle
appelle le constructeur.

- un destructeur virtuel n'est pas different d'une autre methode
virtuelle sur ce point. Dans virtual B::~B(), this peut etre de type
D* ou D derive de B et on peut le retrouver avec un
dynamic_cast<>().



Non.


Peux-tu m'eclairer sur tes propos?



Pendant l'execution du constructeur et du destructeur, l'objet est du
type de la classe construite (et non de la classe la plus derivee).


Je savais pour les constructeurs (ce qui me fait penser que j'ai dit une
betise dans l'autre post, le virtual de construct et destruct est
inutile), mais je ne savais pas pour les destructeurs... Autant le
premier me parait logique autant j'ai du mal a comprendre la raison du
second. Un probleme de ressources associees a la vtbl (la vtbl elle-meme?)?

Appeler un membre virtuel sur this a un comportement defini: la
fonction sera celle de la classe construite ou de l'ancetre la
fournissant (donc c'est un probleme si elle est pure).


Juste. Sauf si la methode virtual appellee n'utilise pas this (12.7/3),
mais je ne vois pas a quoi elle servirait (du debug?).

Appeler un membre virtuel a travers d'un alias de this qui n'est pas
du type construit ou d'un de ses descendants est indefini.


ok.

Les references:


merci.

a+, ld.



Avatar
Jean-Marc Bourguet
Laurent Deniau writes:

Pendant l'execution du constructeur et du destructeur, l'objet est
du type de la classe construite (et non de la classe la plus
derivee).


Je savais pour les constructeurs (ce qui me fait penser que j'ai dit
une betise dans l'autre post, le virtual de construct et destruct
est inutile), mais je ne savais pas pour les destructeurs... Autant
le premier me parait logique autant j'ai du mal a comprendre la
raison du second.


Exactement les raisons symetriques. Par exemple lors de l'execution
du constructeur, les membres des classes descendantes n'ont pas encore
ete construit, pendant l'execution du destructeur ils ont deja ete
detruits.

Un probleme de ressources associees a la vtbl (la vtbl elle-meme?)?

Appeler un membre virtuel sur this a un comportement defini: la
fonction sera celle de la classe construite ou de l'ancetre la
fournissant (donc c'est un probleme si elle est pure).


Juste. Sauf si la methode virtual appellee n'utilise pas this (12.7/3),
mais je ne vois pas a quoi elle servirait (du debug?).


Je ne vois pas ou tu lis ca dans 12.7/3.

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
Laurent Deniau
Jean-Marc Bourguet wrote:
Laurent Deniau writes:


Y a n n R e n a r d wrote:

Bonjour à tous,
Voila mon problème : j'ai un client qui souhaite que toutes les classes
définies dans le projet sur lequel je travaille soient sous la forme
canonique de Coplien (pour ceux qui ne connaissent pas : constructeur par
défaut, constructeur par copie, operateur d'affectation et destructeur
virtuel ou non). Pour que ce soit plus clean (selon eux), le client
demande que toutes les classes dérivent d'une classe de base... Sauf que
je ne vois pas du tout l'intéret de faire ca car je ne vois pas en quoi
ca force à respecter la forme canonique de Coplien.
Concernant l'operateur d'affectation, si je le met virtuel (est ce
quelque chose de propre ?!) comment puis je faire en sorte que les
classes filles utilisent un opérateur correct ? cast dynamique ?
Concernant l'operateur de recopie, là, je vois pas du tout du tout du
tout :)
Bref, je comprends pas du tout cette demande, si quelqu'un pense que
c'est raisonable ou explicable, je veux bien une précision sur
l'utilité...


Je trouve ca effectivement tres interessant et rare de la part d'un
client qui doit deja etre experimente dans la gestion de gros
*projet C++* (d'autre langage OO n'ont pas ces problemes).



Que demande t'il?

- que toutes les classes soient avec
* constructeur par defaut, desole j'ai des classes qui n'en
ont pas et je ne vois aucune raison d'en imposer un
artificiel


Forcer le developpeur a reflechir a l'etat par defaut de son objet, ne
pas se bloquer la possibilite de faire des tableaux de ses objets (pour
optimiser ulterieurement des containeurs?).

J'ai souvent vu des classes avec des constructeurs avec parametres mais
pas de redefinition du constructeur par defaut sans qu'il soit qualifie
protected (desactive), et avec des methodes utilisant des ressources de
l'objet sans verifier qu'elles avaient bien ete initialisees (pensant
venir forcement d'un constructeur avec parametres).

* destructeur: ce n'est pas possible de faire autrement


yep.

* assignement et constructeur de copie: je perds mon temps
a les desactiver dans au moins la moitie de mes classes


ca d'accord. ca simplifie souvent la complexite de l'utilisation de l'objet.

- que toutes les classes derivent d'une classe de base
* c'est impraticable (comment on fait pour imposer la classe
de base de std::vector, de classes derivees a partir
d'elements d'une bibliotheque tierce ?)


Je pense qu'il parle seulement des classes du projet.

* si c'est pour imposer la forme canonique je ne vois pas
comment faire (tiens sauf pour qqch du genre NotCopiable...
mais avec une telle classe de base, definir l'assignement
et le constructeur de copie, c'est de la perversite)
* ca me fait plutot penser a quelqu'un qui a de l'experience
d'un autre langage ou cette classe de base est presente
d'office que du C++ (tiens bizarrement c'etait la mode au
debut du C++ quand pour une partie des gens OO signifiait
SmallTalk)


Apres reflexion et le bug de design sur construct et destruct, je crois
que tu as raison. Ils viennent peut-etre de Java. Ce qui est etonnant,
c'est que la forme Coplien n'a pas de sens en Java. Alors pourquoi la
demande-t-ils?

- de faire faire le travail des constructeurs et destructeurs par

une autre fonction, pourquoi?

Ton client a probalement une vision long terme du projet avec un
soucis de qualite dans l'evolutivite. L'ultra-performance n'est pas
sa priorite. Il vise probablement une progammation differentielle
par contrat, c'est-a-dire que chaque classe de la hierachie fait un
peu du travail puis delegue le reste a sa classe de base. Le virtual
permet de sauter des etapes dans la hierarchie (par ex si un niveau
de classe n'a rien a ajouter ca passe directement a sa classe de
base). Les contrats permettent de verifier qu'a chaque niveau on est
bien de le domaine attendu en entree et en sortie.

Je dirais que c'est tres contraignant sur des petits programmes ou
on a une vue d'ensemble des le depart et que l'evolutivite n'est pas
la priorite. Sur un grand projet, les demandes de ton client sont
tres sensees.



Je ne vois guere de sens. Il me semble pourtant que j'ai l'experience
de gros projets.


Pour terminer, il faut aussi déporter le code du constructeur et du
destructeur dans une fonction séparée, et là, je comprends plus du
tout... genre quelque chose comme ca :
T::T(void)
{
construct();
}


Ca c'est l'inverse des factory.

Je pense que c'est pour du debug (trace, check, message de log) si
construct est virtuelle.



Expliques-toi, je ne vois pas l'utilite de faire ca systematiquement,
meme avec un objectif d'instrumentation.


T::~T(void)
{
destruct();
}


idem si destruct est virtuelle.



A nouveau je ne vois pas l'utilite.


void T::construct(void)
{
// ...
}



void T::destruct(void)
{
// ...
}


est-ce que dans la classe de base elle ne sont pas declaree virtuelles?



Qu'est-ce que ca change?


rien ;-)

Dans ce cas je dirais que soit ils n'ont pas compris le probleme des
methodes virtuelles dans les ctor/dtor, soit ils ont inverse les
construction et ils pensaient a des factory en utilisant construct et
destruct.

Dans les deux cas, ce n'est pas clair.

Pour la forme de Coplien, peut-etre que le client par du principe que le
developpeur devra reflechir au point clefs de l'utilisation de l'objet.
Quitte a les mettre private ou protected pour montre qu'il y a reflechit
mais qu'ils ne sont pas utiles, voir dangeureux.

a+, ld.



Avatar
Laurent Deniau
Jean-Marc Bourguet wrote:
Laurent Deniau writes:


Pendant l'execution du constructeur et du destructeur, l'objet est
du type de la classe construite (et non de la classe la plus
derivee).


Je savais pour les constructeurs (ce qui me fait penser que j'ai dit
une betise dans l'autre post, le virtual de construct et destruct
est inutile), mais je ne savais pas pour les destructeurs... Autant
le premier me parait logique autant j'ai du mal a comprendre la
raison du second.



Exactement les raisons symetriques. Par exemple lors de l'execution
du constructeur, les membres des classes descendantes n'ont pas encore
ete construit, pendant l'execution du destructeur ils ont deja ete
detruits.

Un probleme de ressources associees a la vtbl (la vtbl elle-meme?)?



Je ne parlais pas de la construction/destruction de l'objet, mais de la
construction/destruction de la vtbl. Mais je viens de m'appercevoir que
la norme ne dit pas qu'elle est invalide (ni ton post!). Et je ne sais
pas pourquoi je le pensais quand j'ai ecrit ca, ca n'a pas de sens.

Appeler un membre virtuel sur this a un comportement defini: la
fonction sera celle de la classe construite ou de l'ancetre la
fournissant (donc c'est un probleme si elle est pure).


Juste. Sauf si la methode virtual appellee n'utilise pas this (12.7/3),
mais je ne vois pas a quoi elle servirait (du debug?).



Je ne vois pas ou tu lis ca dans 12.7/3.


C'est le meme probleme que ci-dessus, j'ai lu "indefini" au lieu de
"defini" dans ton post, ce qui m'ammene a la question de pourquoi la
vtbl n'est-elle pas valide avant la fin du ctor et deja invalide au
debut du dtor. Et comme je le dis ci-dessus, ca n'a rien a voir et je me
demande comment j'ai pu penser cela. (je crois que je suis fatique ;-))

Bref "Beaucoup de bruit pour rien" ;-)

desole.

a+, ld.



1 2 3 4 5