Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Vocabulaire.

42 réponses
Avatar
Alexis Guillaume
Bonjour =E0 tous.

Je suis en train de concevoir une hi=E9rarchie de classe en C++ :

class base {
public:
virtual void foo();
};

Dans les commentaires, j'impose que si foo() est d=E9riv=E9e dans une
classe fille, alors cette m=E9thode d=E9riv=E9e doit aussi appeler
explicitement base::foo() apr=E8s avoir fait ce qu'elle voulait. Plus
g=E9n=E9ralement, si on a C qui h=E9rite de B et B qui h=E9rite base, et qu=
e B
et C d=E9rivent foo(), alors C::foo() doit appeler B::foo() et B::foo()
doit appeler base::foo().

Je dois r=E9diger un document de conception et j'ai bien du mal =E0
trouver comment appeler ce genre de fonctions virtuelles. Je pensais =E0
quelque chose comme "m=E9thode virtuelle cha=EEn=E9e"... Mais il y a
s=FBrement mieux et il y a peut-=EAtre m=EAme un mot qui existe d=E9j=E0 po=
ur
cela auquel cas c'est bien s=FBr lui que j'emploirai.

Merci pour vos avis =E9clair=E9s.
Alexis Guillaume.

10 réponses

1 2 3 4 5
Avatar
Michael DOUBEZ
Alexis Guillaume wrote:
Bonjour à tous.

Je suis en train de concevoir une hiérarchie de classe en C++ :

class base {
public:
virtual void foo();
};

Dans les commentaires, j'impose que si foo() est dérivée dans une
classe fille, alors cette méthode dérivée doit aussi appeler
explicitement base::foo() après avoir fait ce qu'elle voulait. Plus
généralement, si on a C qui hérite de B et B qui hérite base, et que B
et C dérivent foo(), alors C::foo() doit appeler B::foo() et B::foo()
doit appeler base::foo().



Je dois rédiger un document de conception et j'ai bien du mal à
trouver comment appeler ce genre de fonctions virtuelles. Je pensais à
quelque chose comme "méthode virtuelle chaînée"... Mais il y a
sûrement mieux et il y a peut-être même un mot qui existe déjà pour
cela auquel cas c'est bien sûr lui que j'emploirai.



Il y a le pattern "chaine de responsabilité" que tu peux employer. Ca a
l'air d'en être une forme (je ne peux pas dire avec les éléments que tu
donnes).

--
Michael
Avatar
Alexis Guillaume
> Il y a le pattern "chaine de responsabilité" que tu peux employer. Ca a
l'air d'en être une forme (je ne peux pas dire avec les éléments qu e tu
donnes).



En effet je me renseigne sur ce pattern et ça a l'air d'être ce que je
veux faire. Merci beaucoup ! :-)

Alexis Guillaume.
Avatar
pjb
Alexis Guillaume writes:

Il y a le pattern "chaine de responsabilité" que tu peux employer. Ca a
l'air d'en être une forme (je ne peux pas dire avec les éléments que tu
donnes).



En effet je me renseigne sur ce pattern et ça a l'air d'être ce que je
veux faire. Merci beaucoup ! :-)



Oui, enfin, c'est le fonctionnement normal en programmation objet
quand on surcharge une méthode, d'appeler la méthode de la superclass.

C'est tellement normal, que dans les langages de programmation objet
normaux, il y a en général un mot clé ou une syntaxe particulière,
quand ce n'est pas automatique.

Par exemple, en Objective-C:

-doSomething
{
[self doSomethingBefore];
[super doSomething]; // ***
[self doSomethingAfter];
}

en Ruby:

def doSomething
doSomethingBefore
super.doSomething
doSomethingAfter
end

ou en Common Lisp:

(defmethod do-something ((self my-class))
(do-something-before)
(call-next-method) ;; ***
(do-something-after))

ou encore:

(defmethod do-something :before ((self my-class))
(do-something-before))

;; La méthode do-something est appelée automatiquement.

(defmethod do-something :after ((self my-class))
(do-something-after))



Tu es en train de documenter quelque chose qui est ce qui devrait se
faire par défaut, car c'est la façon naturelle d'implémenter le
principe de substitution de Lyskov.



Alors la question, c'est si on doit appeler cette méthode dans la
superclasse simplement pour assurer que la post-condition est bien
remplie (étant donnée la pré-condition), ou s'il y a une autre
raison (par exemple, un effet de bord particulier que l'on veut
obtenir.

Dans le premier cas, on n'a rien besoin de documenter car ça doit être
toujours le cas, et il n'y a pas de raison pour qu'une sous-classe ne
puisse pas s'assurer de la post-condition par d'autres voies que la
superclasse (même si en général, un bon programmeur étant faignant
essayera plutôt d'appeler la super classe que de réinventer la roue).

Dans le second cas, il vaudrait mieux avoir une méthode Y distincte
dans la super classe, et documenter simplement que toute surcharge de
la méthode originale X doit s'assurer que cette méthode Y est appelée,
que ce soit directement ou via la méthode X de la superclasse.


Une autre solution serait d'utiliser une méthode crochet, c'est à dire
qu'on défini dans la super classe une méthode WX qui s'assure que la
méthode Y est appelée en même temps que X, la superclasse ne
définissant pas X (ou fournissant une définition par défaut vide), en
spécifiant simplement qu'une sous-classe doit surcharger X (comme elle
le veut, la méthode Y étant appelée automatiquemetn par WX.

--
__Pascal Bourguignon__
Avatar
Fabien LE LEZ
On Wed, 04 Mar 2009 16:27:33 +0100, (Pascal J.
Bourguignon):

Oui, enfin, c'est le fonctionnement normal en programmation objet
quand on surcharge une méthode, d'appeler la méthode de la superclass.



Ben oui, mais justement, C++ n'est pas un langage objet, et n'a
d'ailleurs pas la notion de "méthode".
Avatar
espie
In article ,
Pascal J. Bourguignon wrote:

Oui, enfin, c'est le fonctionnement normal en programmation objet
quand on surcharge une méthode, d'appeler la méthode de la superclass.


[...]

ou en Common Lisp:

(defmethod do-something ((self my-class))
(do-something-before)
(call-next-method) ;; ***
(do-something-after))

ou encore:

(defmethod do-something :before ((self my-class))
(do-something-before))

;; La méthode do-something est appelée automatiquement.

(defmethod do-something :after ((self my-class))
(do-something-after))



Tu es en train de documenter quelque chose qui est ce qui devrait se
faire par défaut, car c'est la façon naturelle d'implémenter le
principe de substitution de Lyskov.



Si je comprend bien, ca marche comme ca par defaut en common-lisp ?

Et tu fais comment quand tu derives pour precisement gerer un cas
particulier, qui ne doit *pas* appeler la methode de la super-classe,
style tout le reste est quasi-identique, mais tu as precisement envie
de ne pas avoir ce comportement la ?

Ou alors, comment tu fais pour fabriquer une classe abstraite, lui
filer certains comportements par defaut, histoire de pas laisser tout
nu une classe rejeton, mais en comprenant bien que tres souvent, il
faudra totalement remplacer le comportement par defaut ?
Avatar
Jean-Marc Bourguet
(Pascal J. Bourguignon) writes:

Alexis Guillaume writes:

>> Il y a le pattern "chaine de responsabilité" que tu peux employer. Ca a
>> l'air d'en être une forme (je ne peux pas dire avec les éléments que tu
>> donnes).
>
> En effet je me renseigne sur ce pattern et ça a l'air d'être ce que je
> veux faire. Merci beaucoup ! :-)

Oui, enfin, c'est le fonctionnement normal en programmation objet quand
on surcharge une méthode, d'appeler la méthode de la superclass.



Bizarre, dans la plupart des cas, ce n'est pas ce que je fais (a commencer
par tous les cas ou la fonction membre est pure dans la classe de base).

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
Michael DOUBEZ writes:

Jean-Marc Bourguet wrote:
> (Pascal J. Bourguignon) writes:
>
>> Alexis Guillaume writes:
>>
>>>> Il y a le pattern "chaine de responsabilité" que tu peux employer. Ca a
>>>> l'air d'en être une forme (je ne peux pas dire avec les éléments que tu
>>>> donnes).
>>> En effet je me renseigne sur ce pattern et ça a l'air d'être ce que je
>>> veux faire. Merci beaucoup ! :-)
>> Oui, enfin, c'est le fonctionnement normal en programmation objet quand
>> on surcharge une méthode, d'appeler la méthode de la superclass.
> Bizarre, dans la plupart des cas, ce n'est pas ce que je fais (a commencer
> par tous les cas ou la fonction membre est pure dans la classe de base).

Une fonction virtuelle pure a peut avoir un corps bien que ce soit assez
rare (sauf peut être quand c'est le destructeur).



Je sais (et dans ce cas la, generalement on appelle la version de la classe
de base). Je n'utilise pas et je prefere fournir une autre fonction avec
un nom explicite, ca reduit la confusion.

En passant, le destructeur est un cas ou le langage impose que la version
de la classe de base soit appelee.

--
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
Michael DOUBEZ
Jean-Marc Bourguet wrote:
(Pascal J. Bourguignon) writes:

Alexis Guillaume writes:

Il y a le pattern "chaine de responsabilité" que tu peux employer. Ca a
l'air d'en être une forme (je ne peux pas dire avec les éléments que tu
donnes).


En effet je me renseigne sur ce pattern et ça a l'air d'être ce que je
veux faire. Merci beaucoup ! :-)


Oui, enfin, c'est le fonctionnement normal en programmation objet quand
on surcharge une méthode, d'appeler la méthode de la superclass.



Bizarre, dans la plupart des cas, ce n'est pas ce que je fais (a commencer
par tous les cas ou la fonction membre est pure dans la classe de base).



Une fonction virtuelle pure a peut avoir un corps bien que ce soit assez
rare (sauf peut être quand c'est le destructeur).

--
Michael
Avatar
pjb
(Marc Espie) writes:

In article ,
Pascal J. Bourguignon wrote:

Oui, enfin, c'est le fonctionnement normal en programmation objet
quand on surcharge une méthode, d'appeler la méthode de la superclass.


[...]

ou en Common Lisp:

(defmethod do-something ((self my-class))
(do-something-before)
(call-next-method) ;; ***
(do-something-after))

ou encore:

(defmethod do-something :before ((self my-class))
(do-something-before))

;; La méthode do-something est appelée automatiquement.

(defmethod do-something :after ((self my-class))
(do-something-after))



Tu es en train de documenter quelque chose qui est ce qui devrait se
faire par défaut, car c'est la façon naturelle d'implémenter le
principe de substitution de Lyskov.



Si je comprend bien, ca marche comme ca par defaut en common-lisp ?



Oui, dans le second cas, quand on utilise :before ou :after.

Dans le premier cas, on utilise (call-next-method) pour indiquer à
quel moment _les_ méthodes des superclasses, ou des classes héritées
en même temps que la classe courante, doivent être appelées.


Et tu fais comment quand tu derives pour precisement gerer un cas
particulier, qui ne doit *pas* appeler la methode de la super-classe,
style tout le reste est quasi-identique, mais tu as precisement envie
de ne pas avoir ce comportement la ?



Dans ce cas là, on n'appelle pas (call-next-method).


Ou alors, comment tu fais pour fabriquer une classe abstraite, lui
filer certains comportements par defaut, histoire de pas laisser tout
nu une classe rejeton, mais en comprenant bien que tres souvent, il
faudra totalement remplacer le comportement par defaut ?



Dans ce cas, on implémente des méthodes par défaut pour la classe
abstraite et les sous-classes peuvent surcharger ces méthodes sans
appeler (call-next-method).


Mais si on utilise l'héritage multiple, il vaut mieux appeler
(call-next-method) et avoir des méthodes par défault neutres dans les
classes "abstraites".


--
__Pascal Bourguignon__
Avatar
pjb
Jean-Marc Bourguet writes:

(Pascal J. Bourguignon) writes:

Alexis Guillaume writes:

>> Il y a le pattern "chaine de responsabilité" que tu peux employer. Ca a
>> l'air d'en être une forme (je ne peux pas dire avec les éléments que tu
>> donnes).
>
> En effet je me renseigne sur ce pattern et ça a l'air d'être ce que je
> veux faire. Merci beaucoup ! :-)

Oui, enfin, c'est le fonctionnement normal en programmation objet quand
on surcharge une méthode, d'appeler la méthode de la superclass.



Bizarre, dans la plupart des cas, ce n'est pas ce que je fais (a commencer
par tous les cas ou la fonction membre est pure dans la classe de base).



Oui, les méthodes virtuelles pures sont pratiques pour permettre au
compilateur de vérifier qu'on a bien fourni une implémentation dans
les sous-classes. Cependant ce n'est pas adapté à un style de
programmation plus dynamique, et ça donne plus de travail à
l'utilisateur de la classe abstraite.

En général je préfère définir une implémentation par défaut pour
toutes mes méthodes, même dans les classes "abstraites".

--
__Pascal Bourguignon__
1 2 3 4 5