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 ?
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::operator=(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.
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 ?
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::operator=(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.
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 ?
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::operator=(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.
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::operator=(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 ?
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::operator=(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 ?
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::operator=(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 ?
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.
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::operator= (B1 const&) (et vice-versa).
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.
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::operator= (B1 const&) (et vice-versa).
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.
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::operator= (B1 const&) (et vice-versa).
elle set impossible comme telle. B1 définit un operateur =
avec B1& en paramètre, pas un A&
En fait si. En fait, B0::operator=(B0 const &) empêche la
création d'un operator= automatique. Un effet de bord est donc
l'appel de A::operator=(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.
elle set impossible comme telle. B1 définit un operateur =
avec B1& en paramètre, pas un A&
En fait si. En fait, B0::operator=(B0 const &) empêche la
création d'un operator= automatique. Un effet de bord est donc
l'appel de A::operator=(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.
elle set impossible comme telle. B1 définit un operateur =
avec B1& en paramètre, pas un A&
En fait si. En fait, B0::operator=(B0 const &) empêche la
création d'un operator= automatique. Un effet de bord est donc
l'appel de A::operator=(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.
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.
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.)
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.
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.
La détection, c'est le problème la plus simple :
if ( typeid( *this ) != typeid( other ) ) ...
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).
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.
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.)
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.
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.
La détection, c'est le problème la plus simple :
if ( typeid( *this ) != typeid( other ) ) ...
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).
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.
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.)
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.
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.
La détection, c'est le problème la plus simple :
if ( typeid( *this ) != typeid( other ) ) ...
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).
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.
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.
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.
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.
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.
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.
On May 7, 4:02 am, James Kanze 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,
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,
On May 7, 4:02 am, James Kanze 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,