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
Christophe Lephay
Arnaud Meurgues wrote:
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 ?


Si je me souviens bien (je pourrais rouvrir le bouquin mais j'ai la flemme),
Coplien n'impose rien et ni ne définit *une* forme canonique. Il présente un
certain nombre de problèmes, montre une façon de le résoudre, et en arrive à
une forme canonique *pour chaque* problème qu'il aborde.

Ce que je pense, c'est que ce que le client veut avant tout, c'est de ne pas
à avoir à utiliser de pointeurs plus qu'offrir une réelle sémantique de
valeur. Après, c'est dur de se faire une idée sans savoir de quel genre de
classes il est question ni sans pouvoir parler avec le dit client. Après
tout, la transcription des désirs du client n'est peut-être pas forcément
exacte (dans la mesure où il ne comprend pas l'objectif de son client, il y
a nécessairement un problème de communication).

Chris

Avatar
Jean-Marc Bourguet
Laurent Deniau writes:

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


Les containeurs de la bibliotheque standard sont utilisables sans
constructeur par defaut. Il faut simplement fournir un objet a
copier.

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


J'ai l'impression que tu oublies que des qu'il y a un constructeur
declare par le programmeur, le constructeur par defaut n'est pas
declare implicitement.

[...]
- 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 on utilise des choses d'ailleurs (allez, on definit un streambuf)
pourquoi s'imposer de l'heritage multiple? Je n'aime pas les regles
trop absolues.

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


Ma boule de cristal est en panne. Deux possibilites:
- ils n'ont pas compris grand chose au C++ et ont mal digere un
bouquin ou des conseils
- l'OP a mal compris les demandes.

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
Andre Heinen
On Thu, 18 Nov 2004 14:19:52 +0100, Laurent Deniau
wrote:

- Les constructeurs ne peuvent pas etre virtuels, donc forcement dans
B::B(), this est de type B*.


B*, mais pas D*.

Et on ne peut pas appeler de methode
virtuelle dans le constructeur.


Si, mais on risque une surprise.

Prenons une base B et une classe dérivée D avec une fonction
virtuelle v().

Lorsque tu instancies un D, le constructeur de B est appelé en
premier lieu. Il peut appeler v(), mais pendant l'exécution du
constructeur le mécanisme des fonctions virtuelles est désactivé:
B::B() appelera donc non pas D::v() mais B::v(). C'est parce que
les membres de D ne sont pas encore initialisés, et donc on ne
prend pas le risque que D::v() y touche.

--
Andre Heinen
My address, rot13-encoded: n qbg urvara ng rhebcrnayvax qbg pbz

Avatar
drkm
Laurent Deniau writes:

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.


Mais il ne s'agit pas de vtable. Il s'agit d'objets. Lorsque tu
construis un objet, il est construit petit à petit. La première étape
est de construire l'objet de base le plus haut dans la hiérarchie,
puis celui juste en dessous, etc. Donc un constructeur est appelé
pour chaque type ancêtre du type construit, en partant de la racine de
la hiérarchie, jusqu'au type effectivement construit.

Donc lorsque l'on rentre dans un constructeur, ses différents
sous-objets ont déjà été construits (mais pas l'éventuel objet dont il
est lui-même un sous-objet).

Imagine par exemple ce qui pourrait se passer dans le bout de code
suivant, si le type dynamique de this n'était pas égal au type
statique dans les constructeurs :

struct A {
A() {
}
virtual void f() {
}
} ;

struct B : A {
B()
: myC( getSomeImportantData() ) {
}
virtual void f() {
myC->doSomeImportantTask() ;
}
private:
C * myC ;
} ;


Pour le destructeur, c'est exactement l'inverse.

--drkm

Avatar
drkm
Jean-Marc Bourguet writes:

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.


Il ne s'agirait pas plutôt de ses ascendants ?

--drkm

Avatar
Jean-Marc Bourguet
drkm writes:

Jean-Marc Bourguet writes:

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.


Il ne s'agirait pas plutôt de ses ascendants ?


Correct.

--
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
drkm
drkm writes:

Imagine par exemple ce qui pourrait se passer dans le bout de code
suivant, si le type dynamique de this n'était pas égal au type
statique dans les constructeurs :

struct A {
A() {
}
virtual void f() {
}
} ;

struct B : A {
B()
: myC( getSomeImportantData() ) {
}
virtual void f() {
myC->doSomeImportantTask() ;
}
private:
C * myC ;
} ;


Oops. Cet exemple est parfaitement anodin. Il faut bien sûr faire
appel à f() dans A::A() pour qu'il ait un sens (et la construction
d'un objet de type B, évidemment) :

struct A {
A() {
this->f() ;
}
virtual void f() {
}
} ;

struct B : A {
B()
: myC( getSomeImportantData() ) {
}
virtual void f() {
myC->doSomeImportantTask() ;
}
private:
C * myC ;
} ;

--drkm

Avatar
Yann Renard
Bonjour à tous,

je ne prends pas le temps de répondre à chacun indépendament, j'espere
que vous ne me blamerez pas :)

Merci pour vos réactions nombreuses, qui me confirment que je ne suis
pas completement sur une autre planete. Il est exact que le client a un
passé assez fort sur Java. Pour ce qui est d'eclaircir le probleme avec
lui, je ne suis pas en contact direct. Les explications arrivent donc
plutot "doucement".

Merci encore,

Yann Renard

PS :
- le client ne demande pas explicitement la forme canonique de Coplien,
il demande l'ensemble des paramètres requis par cette forme, je l'ai
donc appelé comme tel :)
- je ne connaissais pas les particularités d'appel des méthodes
virtuelles dans le constructeur, très interessant !
Avatar
kanze
"Christophe Lephay" wrote in message
news:<419cba62$0$1313$...
Arnaud Meurgues wrote:
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 ?


Si je me souviens bien (je pourrais rouvrir le bouquin mais j'ai la
flemme), Coplien n'impose rien et ni ne définit *une* forme canonique.
Il présente un certain nombre de problèmes, montre une façon de le
résoudre, et en arrive à une forme canonique *pour chaque* problème
qu'il aborde.


Coplien est un des pioniers des modèles de conception. Ce n'est pas lui
qui a inventé l'expression « design patterns » (il les appellent des
idiomes), mais c'est bien de ça qu'il s'agit déjà dans son livre. La
forme « canonique » apparaît dans un chapitre où il parle des types avec
une sémantique de valeur. C'est donc une forme canonique pour les types
avec une sémantique de valeur.

Malheureusement, il l'a bien nommé « forme canonique », sans autres
précisions.

Ce que je pense, c'est que ce que le client veut avant tout, c'est de
ne pas à avoir à utiliser de pointeurs plus qu'offrir une réelle
sémantique de valeur.


J'ai plutôt l'impression que le client a lu un peu à droit et à gauche,
sans rien avoir compris, et cherche maintenant à imposer une collection
d'idées prises de ce qu'il a lu, sans savoir pourquoi, ni même si elles
conviennent. En particulier :

- La forme cononique s'applique aux classes à sémantique de valeur.
Sauf exceptions, une classe à sémantique de valeur ne doit être ni
une classe de base, ni une classe dérivée. (Coplien traite
l'exception dans son idiome lettre-envelope.) La forme canonique
*est* valable quand il s'agit d'une classe à sémantique de valeur,
mais pas autrement.

- De point de vue de la conception, dans un langage au typage
statique, comme le C++ (ou le Java), la présence du classe de base
universelle doit être considérée une erreur de conception. Elle est
parfois nécessaire quand le langage n'a pas les types types
génériques -- dans ce cas-là, c'est un « necessary evil », comme on
dit en anglais. Mais même dans le C++ primitif, l'existance de
<generic.h> permettait qu'on les évite.

--
James Kanze GABI Software http://www.gabi-soft.fr
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
Christophe Lephay
wrote:
J'ai plutôt l'impression que le client a lu un peu à droit et à
gauche, sans rien avoir compris, et cherche maintenant à imposer une
collection d'idées prises de ce qu'il a lu, sans savoir pourquoi, ni
même si elles conviennent. En particulier :


Ce que veut le client, selon moi, c'est juste des pointeurs intelligents...

Chris

1 2 3 4 5