PHWinfo banniere

Titres
PORTAIL ANNUAIRE ARTICLES COMPARATEUR HÉBERGEURS DEVIS FORUMS RÉDUCTEUR D'URL
Précédent   PHWinfo > Autres forums > Forum Programmation & Conception > fr.comp.lang.c++ > Gestion de l'assignation consanguine
S'inscrire FAQ Membres Recherche Messages du jour Marquer les forums comme lus
Gestion de l'assignation consanguine

Réponse
 
LinkBack Outils de la discussion
Vieux 30/04/2008, 01h59   #1
Mickaël Wolff
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Gestion de l'assignation consanguine

Bonjour,

Si on a les trois classes suivantes :

class A
{
public:
virtual A & operator=(A const & rvalue) ;

/* ... */
} ;

class B0 : public A
{
public:
virtual A & operator=(B0 const & rvalue) ;
/* ... */
} ;

class B1 : public A
{
public:
virtual A & operator=(B1 const & rvalue) ;
/* ... */
} ;

Dans l'usage suivant :

B0 b0 ;
B1 b1 ;

A & b0_a = static_cast<A &>(b0) ;
b1 = b0_a ;

Dans la pratique, comment devrais-je gérer une telle affectation ?
Lever une exception car c'est un non sens ? Et surtout, comment je le
détecte dans l'affectation ? La solution la plus directe que je vois
dans le cas où on gère est un dynamic_cast dans B0:perator=(A const
&). J'avoue que je serais partisan de rendre l'opération silencieuse,
mais je risque de me surprendre, en perdant des information lors
d'affectations.

Que faites-vous pratiquement dans ce cas ?

Merci !
--
Mickaël Wolff aka Lupus Michaelis
http://lupusmic.org
  Réponse avec citation
Vieux 30/04/2008, 02h31   #2
Sylvain SF
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Gestion de l'assignation consanguine

Mickaël Wolff wrote on 30/04/2008 02:59:
>
> class A {
> public:
> virtual A & operator=(A const & rvalue) ;
> } ;
>
> class B0 : public A {
> public:
> virtual A & operator=(B0 const & rvalue) ;
> } ;
>
> class B1 : public A {
> public:
> virtual A & operator=(B1 const & rvalue) ;
> } ;
>
> B0 b0 ;
> B1 b1 ;
> A & b0_a = static_cast<A &>(b0) ;
> b1 = b0_a ;
>
> Dans la pratique, comment devrais-je gérer une telle affectation ?


elle set impossible comme telle.
B1 définit un operateur = avec B1& en paramètre, pas un A&

> Lever une exception car c'est un non sens ? Et surtout, comment je le
> détecte dans l'affectation ?


si l'affectation est un non-sens, les operéateurs d'affectation
devraient être privés pour éviter ces non-sens.

> La solution la plus directe que je vois dans le cas où on gère
> est un dynamic_cast dans B0:perator=(A const &).


si en effet initialiser un B1 depuis un A a un sens (affectation des
attributs de base et déduction et/ou choix par défaut pour les membres
propres à B1) cet opérateur sur B0 et/ou B1 est requis.

> J'avoue que je serais partisan de rendre l'opération silencieuse,
> mais je risque de me surprendre, en perdant des information lors
> d'affectations.


si la perte signifie que l'instance sera caduque, interdissez les
affectations; si les classes sont transposables (A = coordonnées,
B0 = cartesiennes, B1 = polaires) offrez ces opérateurs et pourquoi
pas un B0:perator= (B1 const&) (et vice-versa).

Sylvain.
  Réponse avec citation
Vieux 30/04/2008, 09h06   #3
James Kanze
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Gestion de l'assignation consanguine

On Apr 30, 2:59 am, Mickaël Wolff <mickael.wo...@laposte.net> wrote:

> Si on a les trois classes suivantes :


> class A
> {
> public:
> virtual A & operator=(A const & rvalue) ;
> /* ... */
> } ;


> class B0 : public A
> {
> public:
> virtual A & operator=(B0 const & rvalue) ;
> /* ... */
> } ;


> class B1 : public A
> {
> public:
> virtual A & operator=(B1 const & rvalue) ;
> /* ... */
> } ;


> Dans l'usage suivant :


> B0 b0 ;
> B1 b1 ;


> A & b0_a = static_cast<A &>(b0) ;
> b1 = b0_a ;


> Dans la pratique, comment devrais-je gérer une telle
> affectation ?


Dans la pratique, tu dois te démander si ça a un sens. Au moins
dans les applications que je fais, le polymorphisme s'applique
surtout à des objets ayant une identité, et donc, qui ne
supporte ni l'affectation ni la copie.

Sinon, il faut que tu définisses ce que ça signifie dans des cas
comme ceci.

Considère, par exemple, ton code. D'abord, virtuel ou non, tes
opérateurs d'affectation dans les classes dérivées ne
supplantent pas la fonction virtuelle dans la classe de base,
parce qu'ils n'ont pas les mêmes paramètres. Pour qu'il y a
supplantage, il faut définir un opérateur avec la même signature
dans les classes dérivées, c-à-d :

class B0 : public A {
{
public:
virtual B0& operator=( A const& other ) ;
// ...
} ;

(Que l'opérateur renvoie un B0& ou un A&, en revanche, n'a pas
d'importance, puisque le C++ supporte les types de retour
co-variants.)

Du coup, ton code ne passe pas le compilateur, parce que
l'opérateur d'affectation de b1 exige bien un B1 (l'opérateur
d'affectation dans B1 cache bien celui dans A), et tu lui passe
un A. (Pour les paramètres, il n'y a que le type statique qui
compte.)

> Lever une exception car c'est un non sens ?


Est-ce un non sens, en voilà la question ? Dans les rares cas
où l'affectation d'un type polymorphique aient du sens, ce n'est
pas forcement un non sens. Encore, tout dépend. Je vois tout de
suite trois possibilités :

1. On n'accepte l'affectation qu'entre des types dynamiques
identiques. Mais dans ce cas-là, je me démande si on veut
réelement l'affectation (ou la polymorphisme) ; pour
certaines opérations (l'affectation), on n'est pas du tout
polymorphique, et pour d'autres si. C'est en tout cas une
violation flagrante du LSP.

S'il le faudrait, j'interdirais l'affectation au niveau de
la classe de base, et ne l'implémenterait qu'au niveau des
classes dérivées. Si le client veut affecter, il faut qu'il
sache avoir des instances de la même dérivée, et qu'il
utilise leur interface. (Par exemple, qu'il ait fait un
dynamic_cast avant, pour traiter un cas spécial.)

Dans la pratique, ce cas arrive facilement quand la classe
de base représente une qualité plutôt indépendante du rôle
de la classe, quelque chose comme PersistentObject. Dans ce
cas-là, en revanche, on ne traite avec la classe de base que
dans les fonctions qui gèrent cette qualité, ici par
exemple, les fonctions d'entrée/sortie. Et l'affectation se
fera bien toujours avec des classes dérivées.

2. Les classes dérivées représentent une famille, avec un état
abstrait commun. (Je ne peux malheureusement pas penser à de
bons exemples ; je crois que le cas ne s'est jamais
présenté dans mes applications.) Dans ce cas-là, il s'agit
d'écrire un opérateur d'affectation qui extrait l'état
commun, quelque soit le type à droit. Dans le cas le plus
général, il faudrait le « double dispatch », que la
fonction réelement appelée dépend à la fois du type de
l'objet à gauche, et de celui à droit.

Dans ce cas-ci, je ferais plutôt une fonction virtualle
assign() dans la classe de base, avec des surcharges pour
toutes les classes dérivées (implémentation classique du
double dispatch), ou qui cherche la fonction à appeler dans
un map (autre implémentation du double dispatch) ;
l'opérateur d'affectation se contentera d'appeler cette
fonction. Ou les opérateurs d'affectation, plutôt ; il en
faudrait au moins deux dans chaque classe dérivée -- un de
copie, pour empêcher que le compilateur en génère le sien,
et un qui prend une référence à la classe de base, pour
pouvoir affecter les d'autres types dérivés.

3. Enfin, on a réelement à faire avec une valeur polymorphique,
dont le type dynamique fasse partie de la valeur, et doit
être changé lors de l'affectation. Dans ce cas-ci, il faut
l'idiome du lettre/enveloppe. C-à-d que le type de base
contient un pointeur à l'objet réelement polymorphique, et y
renvoie tous les opérations. Et que tous les objets déclarés
soit du type de base, et que l'affectation fasse un clone de
l'objet contenu par l'objet à droit. Ça marche pas mal, mais
c'est un peu lourd, avec un clonage à chaque affectation ou
copie. (Dans le cas où les objets sont immutable, en dehors
de l'affectation, on peut éviter le clonage en se servant
d'un glaneur de cellules, ou éventuellement d'un comptage de
références. Ce qui le rend réelement utilisable, dans
beaucoup de cas.)

> Et surtout, comment je le détecte dans l'affectation ?


La détection, c'est le problème la plus simple :

if ( typeid( *this ) != typeid( other ) ) ...

Savoir ce qu'il faut faire (c-à-d la conception) qui est plus
difficile.

> La solution la plus directe que je vois dans le cas où on gère
> est un dynamic_cast dans B0:perator=(A const &). J'avoue que
> je serais partisan de rendre l'opération silencieuse, mais je
> risque de me surprendre, en perdant des information lors
> d'affectations.


> Que faites-vous pratiquement dans ce cas ?


Je les évite, autant que possible. Dans la pratique, je trouve
qu'ils apparaissent assez rarement, et quand ils apparaissent,
ou bien, je me trouve dans le cas 1, ci-dessus, mais celui qui
veut affecter sait toujours très bien le type (suite à un
dynamic_cast au retour de la lecture, par exemple), et le
problème ne se pose pas réelement, ou je me trouve dans le cas
3, mais avec des objets immutable, et je m'en tire en simplement
affectant un pointeur (intelligent, genre boost::shared_ptr, si
je n'ai pas de glaneur de cellules).

--
James Kanze (GABI Software) email:james.kanze@gmail.com
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
  Réponse avec citation
Vieux 30/04/2008, 13h14   #4
Mickaël Wolff
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Gestion de l'assignation consanguine

Sylvain SF a écrit :
> elle set impossible comme telle.
> B1 définit un operateur = avec B1& en paramètre, pas un A&


En fait si. En fait, B0:perator=(B0 const &) empêche la création
d'un operator= automatique. Un effet de bord est donc l'appel de
A:perator=(A const &) à l'affectation d'un A. C'est du moins le
comportement que j'observe avec gcc 4.3.0, et il ne me parait pas aberrant.

>> Lever une exception car c'est un non sens ? Et surtout, comment je le
>> détecte dans l'affectation ?

>
> si l'affectation est un non-sens, les operéateurs d'affectation
> devraient être privés pour éviter ces non-sens.


Effectivement, c'est une solution à envisager.

> si la perte signifie que l'instance sera caduque, interdissez les
> affectations; si les classes sont transposables (A = coordonnées,
> B0 = cartesiennes, B1 = polaires) offrez ces opérateurs et pourquoi
> pas un B0:perator= (B1 const&) (et vice-versa).


Merci pour ta réponse.

Je répondrai à James un peu plus tard, car sa réponse va me demander
un peu beaucoup de réflexions et d'essais avant de pouvoir apporter une
réponse pertinente.

--
Mickaël Wolff aka Lupus Michaelis
http://lupusmic.org
  Réponse avec citation
Vieux 02/05/2008, 08h41   #5
James Kanze
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Gestion de l'assignation consanguine

On Apr 30, 2:14 pm, Mickaël Wolff <mickael.wo...@laposte.net> wrote:
> Sylvain SF a écrit :


> > elle set impossible comme telle. B1 définit un operateur =
> > avec B1& en paramètre, pas un A&


> En fait si. En fait, B0:perator=(B0 const &) empêche la
> création d'un operator= automatique. Un effet de bord est donc
> l'appel de A:perator=(A const &) à l'affectation d'un A.
> C'est du moins le comportement que j'observe avec gcc 4.3.0,
> et il ne me parait pas aberrant.


En fait, non. Tu ne trouves l'operator=( A const& ) que parce
que tu affectes à travers un A. Rappelons comment se passe les
choses :

-- Le compilateur recherche le nom (ici, operator=). Dans le
cas d'un opérateur, cette recherche est un peu spéciale,
parce qu'il considère à la fois des fonctions libres et des
fonctions membre de la classe. (Il fait deux recherches
plus ou moins indépendantes.) Mais dans le cas de
l'opérateur d'affectation, ça ne change rien, parce qu'on
n'a pas le droit d'en fournir un qui n'est pas membre. La
recherche du nom se fait selon les types statiques
(obligatoirement, puisque c'est tout ce que connaît le
compilateur, et s'arrête là où le nom est trouvé pour la
première fois. C-à-d que si on recherche un operator= avec à
gauche de l'affectation un B0, le compilateur va trouver
B0:perator=. Toujours, parce que cette fonction ne peut
pas ne pas exister. Et il s'arrête là ; il ne regarde pas
dans les classes de base.

-- Ensuite, il y a la résolution des surcharges, mais seulement
parmi les fonctions que le compilateur a trouvé avant. Donc,
dans le cas où l'expression à gauche de l'affectation a le
type B0, que parmi les operator= de B0. Si tu essaies
d'affecter un A (ou une expression dont le type statique est
A, indépendamment du type dynamique de l'objet), et que B0
n'a pas elle-même un operator= qui prend un A, le
compilateur doit te rejeter.

-- Enfin, seulement une fois la résolution du surcharge finie,
le compilateur considère si la fonction est virtuelle ou
non.

Donc, avec les classes que tu avais définies :

B0* pba = new B0 ;
B0* pbb = new B0 ;
A* paa = pb0a ;
A* pab = pb0b ;
*paa = *pab ; // légal, appelle A:perator=(A const&)
*paa = *pbb ; // légal, appelle A:perator=(A const&)
*pba = *pab ; // illégal
*pba = *pbb ; // légal, appelle B0:perator=(B0 const&)

Si, dans A, l'operator=(A const&) est virtuel, *et* il est
supplanté dans B0 (avec un operator=(A const&)), alors, les deux
premiers appels seront virtuels, et appelleront
B0:perator=( A const& ). Mais il faut bien les deux
conditions : et que la fonction en A soit virtuelle, et qu'il y
a un supplantage avec exactement les mêmes paramètres (et la
même const-ité) dans B0.

--
James Kanze (GABI Software) email:james.kanze@gmail.com
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
  Réponse avec citation
Vieux 07/05/2008, 01h02   #6
Mickaël Wolff
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Gestion de l'assignation consanguine

James Kanze a écrit :

> Dans la pratique, tu dois te démander si ça a un sens. Au moins
> dans les applications que je fais, le polymorphisme s'applique
> surtout à des objets ayant une identité, et donc, qui ne
> supporte ni l'affectation ni la copie.


Qu'est-ce que tu appelles une identité ?

> class B0 : public A {
> {
> public:
> virtual B0& operator=( A const& other ) ;
> // ...
> } ;


Oui, en fait j'ai mal posé mes exemples. Finalement, dans le cas où
j'avais besoin d'affectations et de comparaisons virtuelles pour me
libérer de la nature des objets.


> (Que l'opérateur renvoie un B0& ou un A&, en revanche, n'a pas
> d'importance, puisque le C++ supporte les types de retour
> co-variants.)


Ça j'avais compris


> 1. On n'accepte l'affectation qu'entre des types dynamiques
> identiques. Mais dans ce cas-là, je me démande si on veut
> réelement l'affectation (ou la polymorphisme) ; pour
> certaines opérations (l'affectation), on n'est pas du tout
> polymorphique, et pour d'autres si. C'est en tout cas une
> violation flagrante du LSP.


LSP ~= interchangeabilité ?

> S'il le faudrait, j'interdirais l'affectation au niveau de
> la classe de base, et ne l'implémenterait qu'au niveau des
> classes dérivées. Si le client veut affecter, il faut qu'il
> sache avoir des instances de la même dérivée, et qu'il
> utilise leur interface. (Par exemple, qu'il ait fait un
> dynamic_cast avant, pour traiter un cas spécial.)


Ok.

> Dans la pratique, ce cas arrive facilement quand la classe
> de base représente une qualité plutôt indépendante du rôle
> de la classe, quelque chose comme PersistentObject. Dans ce
> cas-là, en revanche, on ne traite avec la classe de base que
> dans les fonctions qui gèrent cette qualité, ici par
> exemple, les fonctions d'entrée/sortie. Et l'affectation se
> fera bien toujours avec des classes dérivées.


C'est certainement ce qui m'arrive. Pour être concret, j'ai une classe
abstraite message. Cette classe fournit des services de base (canal
d'adressage du message), et enveloppe les données transmises. J'ai
essayé de penser à un système générique pour pouvoir les envoyer de la
vue au contrôleur et du modèle à la vue.


> 3. Enfin, on a réelement à faire avec une valeur polymorphique,
> dont le type dynamique fasse partie de la valeur, et doit
> être changé lors de l'affectation. Dans ce cas-ci, il faut
> l'idiome du lettre/enveloppe.


C'est marrant que tu parles d'enveloppe alors que j'envoie des messages.

> La détection, c'est le problème la plus simple :
>
> if ( typeid( *this ) != typeid( other ) ) ...


Certes.

> Je les évite, autant que possible. Dans la pratique, je trouve
> qu'ils apparaissent assez rarement, et quand ils apparaissent,
> ou bien, je me trouve dans le cas 1, ci-dessus, mais celui qui
> veut affecter sait toujours très bien le type (suite à un
> dynamic_cast au retour de la lecture, par exemple), et le
> problème ne se pose pas réelement, ou je me trouve dans le cas
> 3, mais avec des objets immutable, et je m'en tire en simplement
> affectant un pointeur (intelligent, genre boost::shared_ptr, si
> je n'ai pas de glaneur de cellules).


Merci pour toutes ces infos, ça m'a bien aidé à avancer. Même si je
suis de plus en plus convaincu d'avoir écrit une n-ième usine à gaz. :-/

Pas grave, je finirais par appliquer KISS ! Un jour.

--
Mickaël Wolff aka Lupus Michaelis
http://lupusmic.org
  Réponse avec citation
Vieux 07/05/2008, 09h02   #7
James Kanze
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Gestion de l'assignation consanguine

On May 7, 2:02 am, Mickaël Wolff <mickael.wo...@laposte.net> wrote:
> James Kanze a écrit :


> > Dans la pratique, tu dois te démander si ça a un sens. Au moins
> > dans les applications que je fais, le polymorphisme s'applique
> > surtout à des objets ayant une identité, et donc, qui ne
> > supporte ni l'affectation ni la copie.


> Qu'est-ce que tu appelles une identité ?


C'est qu'une opération sur un objet n'en vaut pas la même
opération sur un autre, même si la « valeur » est la même.
L'exemple typique (mais bien simplifié), c'est un compte en
banque, et une valeur qu'on y vire ou prélève. Le compte a une
identité ; faire la virement sur une copie de l'objet, ou un
autre objet qui a par hazard la même valeur ne va pas. La valeur
qu'on y vire ou prélève, en revanche, n'a pas d'identité : 100
Euros, c'est 100 Euros, que ce soit une copie ou non.

(Dans la pratique, il arrive qu'on fasse les copies des objets
ayant une identité, dans la gestion des transactions, par
exemple. Mais chaque opération s'effectue quand même sur une
instance précise de l'objet. On ne copie ni n'affecte pas
librement, mais seulement dans une contexte bien définie -- où
il serait bien acceptable, voire préférable, de faire
l'affectation ou la copie au moyen d'une fonction explicite,
plutôt que de se servir de l'opérateur.)

> > class B0 : public A {
> > {
> > public:
> > virtual B0& operator=( A const& other ) ;
> > // ...
> > } ;


> Oui, en fait j'ai mal posé mes exemples. Finalement, dans le
> cas où j'avais besoin d'affectations et de comparaisons
> virtuelles pour me libérer de la nature des objets.


Les comparaisons ne présentent pas forcément tous les problèmes
des affectations. Si on suppose que le type dynamique fasse
partie de la « valeur », == renvoie faux dès que les types
sont différents (ce qui peut se faire simplement avec typeid).
Tandis que l'affectation n'est tout bonnement impossible entre
des types (dynamiques) différents.

> > (Que l'opérateur renvoie un B0& ou un A&, en revanche, n'a pas
> > d'importance, puisque le C++ supporte les types de retour
> > co-variants.)


> Ça j'avais compris


> > 1. On n'accepte l'affectation qu'entre des types dynamiques
> > identiques. Mais dans ce cas-là, je me démande si on veut
> > réelement l'affectation (ou la polymorphisme) ; pour
> > certaines opérations (l'affectation), on n'est pas du tout
> > polymorphique, et pour d'autres si. C'est en tout cas une
> > violation flagrante du LSP.


> LSP ~= interchangeabilité ?


Liskov Substitution Principle. En fait, oui, c'est un peu
l'interchangeabilité -- on doit pouvoir utiliser un Derived
partout ou un Base est démandé.

En fait, c'est lié à la notion du contrat : la base définit un
contrat, et tout dérivée doit le respecter. Et la
substitutabilité ne vaut, évidemment, que dans le cas où le
client respecte sa partie du contrat. (On peut, par exemple,
imaginer le cas où le code client ne marche qu'à cause des aléas
de l'implémentation de la base, et non à cause de quelque chose
de garantie par la base.) En gros, la dérivée ne doit pas
imposer des préconditions plus contraignantes, et doit garantir
des postconditions au moins aussi fortes que la base. Or, dans
ce que tu proposes, l'affectation d'une dérivée a la
précondition que ce qu'on affecte ait le type dérivée, et non
simplement base.

Mais comme d'habitude, ce n'est pas toujours aussi simple. Le
contrat peut être que l'affectation n'est admise que si
certaines conditions sont rempli. (Dans la bibliothèque
standard, par exemple, le contrat d'affectation d'un itérateur
exige que l'itérateur à droit de l'affectation n'ait pas une
valeur singulaire, c-à-d qu'il ne soit pas construit par le
constructeur par défaut.) Mais personnellement, je n'aime pas
trop que l'opérateur d'affectation ait des préconditions ; dans
de tels cas, je préfère de loin l'utilisation d'une fonction
nommée.

> > S'il le faudrait, j'interdirais l'affectation au niveau de
> > la classe de base, et ne l'implémenterait qu'au niveau des
> > classes dérivées. Si le client veut affecter, il faut qu'il
> > sache avoir des instances de la même dérivée, et qu'il
> > utilise leur interface. (Par exemple, qu'il ait fait un
> > dynamic_cast avant, pour traiter un cas spécial.)


> Ok.


> > Dans la pratique, ce cas arrive facilement quand la classe
> > de base représente une qualité plutôt indépendante du rôle
> > de la classe, quelque chose comme PersistentObject. Dans ce
> > cas-là, en revanche, on ne traite avec la classe de base que
> > dans les fonctions qui gèrent cette qualité, ici par
> > exemple, les fonctions d'entrée/sortie. Et l'affectation se
> > fera bien toujours avec des classes dérivées.


> C'est certainement ce qui m'arrive. Pour être concret, j'ai
> une classe abstraite message. Cette classe fournit des
> services de base (canal d'adressage du message), et enveloppe
> les données transmises. J'ai essayé de penser à un système
> générique pour pouvoir les envoyer de la vue au contrôleur et
> du modèle à la vue.


Ce qui suggère (à moi, et sans connaître toutes les contraintes)
l'interdiction de l'affectation dans la classe de base, avec son
implémentation éventuellement dans les classes dérivées.

Un autre alternatif serait de traiter le message comme si
c'était un espèce d'entité, même s'il n'en est pas une
logiquement, et de n'en copier que les pointeurs. (Puisque
logiquement, un message ne contiendrait pas d'autres pointeurs,
et donc, des cycles sont par définition impossible, on pourrait
très bien se servir de boost::shared_ptr dans ce cas pour glaner
les cellules, si on n'a pas d'autre glaneur de cellules.) A
priori, j'imagine qu'un message, une fois initialisé, est
immutable ; qu'on transmet des copies (valeur) ou des pointeurs
(identité) ne change donc strictement rien, en dehors des
questions de la gestion de la mémoire.

--
James Kanze (GABI Software) email:james.kanze@gmail.com
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
  Réponse avec citation
Vieux 08/05/2008, 16h26   #8
Alexandre Abreu
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Gestion de l'assignation consanguine

On May 7, 4:02 am, James Kanze <james.ka...@gmail.com> wrote:
>
> En gros, la dérivée ne doit pas
> imposer des préconditions plus contraignantes, et doit garantir
> des postconditions au moins aussi fortes que la base.


Je ne veux pas "hijacker" le sujet mais juste une remarque a propos de
cette affirmation.
C'est qquechose qu'on entend souvent et qui est dit et repete quand on
parle de contrat / interface
et qu'on evoque differentes implementations de ce contrat dans le
temps.

Par contre, c'est quelquechose qui m'a toujours plus ou moins derange
(bien que je l'utilise
de cette facon) car j'ai l'impression que tolerer des preconditions
moins contraignantes
et / ou des postconditions plus contraignantes brise le contrat d'une
certaine facon. Je n'ai
jamais encore pu accepter cette affirmation de but en blanc, peut etre
parce qu'il me manque
un element, je ne sais pas ...

Si je vais dans une chaine de restos qui exige que j'apporte mon vin,
et que j'ai l'habitude d'aller dans
un resto de cette chaine qui a choisi d'avoir une carte de vin et donc
de me lever la contrainte
d'aller chercher mon vin moi meme; puis que d'un coup je change de
resto
et que, contre toute attente, lui refuse ... me semble que c'est moi
qui ait brise le contrat initial non?
LSP se trouve plutot mal en point dans ce temps la,

Alex




  Réponse avec citation
Réponse


Outils de la discussion

Règles de messages
Vous ne pouvez pas créer de nouvelles discussions
Vous ne pouvez pas envoyer des réponses
Vous ne pouvez pas envoyer des pièces jointes
Vous ne pouvez pas modifier vos messages

Les balises BB sont activées : oui
Les smileys sont activés : oui
La balise [IMG] est activée : oui
Le code HTML peut être employé : non
Trackbacks are oui
Pingbacks are oui
Refbacks are oui


Fuseau horaire GMT +1. Il est actuellement 07h11.


Édité par : vBulletin® version 3.7.2
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.2.0 RC5 Tous droits réservés.
Version française #16 par l'association vBulletin francophone
PHWinfo est un site Éducation Sans Frontières
Ad Management by RedTyger
©Tous droits réservés par les parties respectives
Page generated in 0,23557 seconds with 16 queries