Cette action est irreversible, confirmez la suppression du commentaire ?
Signaler le commentaire
Veuillez sélectionner un problème
Nudité
Violence
Harcèlement
Fraude
Vente illégale
Discours haineux
Terrorisme
Autre
Michael DOUBEZ
Bonsoir à tous,
je me permets de faire un post différent pour une question que j'ai posé la dernière fois.
Quelle solution vous utilisez concernant l'utilisation de méthodes virtuelles dans une classe dérivée, qui appellent la même fonction de la base:
//Méthode 1 class Base { public: virtual void foo() { //some work } };
class Derived { public: virtual void foo() { Base::foo(); // some other work } };
//Méthode 2 class Base { private: virtual void fooImpl() = 0; public: void foo() { //some work fooImpl(); } };
class Derived { private: virtual void fooImpl() { // some other work } };
Methode 1 et Methode 2 ne sont pas équivalente: dans la Methode 2 fooImpl est une virtuelle pure et donc Base ne peut pas etre instanciée. La délégation à la base dérivée fait donc partie du contrat.
L'avantage de la méthode 1 étant la simplicité, mais l'inconvénient étant un oubli possible d'appeler Base::foo().
La seconde ayant l'avantage de ne pas pemettre l'omission de la redéclaration de la fonction, mais est plus lourde à utiliser.
Si Derived hérite publiquement de Base, j'utilise la Méthode 2. Sinon, ça n'a pas grande importance mais j'irai quand même aussi vers la Méthode 2.
J'ai l'impression que avec Méthode 1, il y a un plus grand risque de violer LSP. Je ne vois pas d'exemple où j'utiliserai cette méthode (à par pour intégrer un code dont je n'ai pas le contrôle).
Michael
Bonsoir à tous,
je me permets de faire un post différent pour une question que j'ai posé
la dernière fois.
Quelle solution vous utilisez concernant l'utilisation de méthodes
virtuelles dans une classe dérivée, qui appellent la même fonction de la
base:
//Méthode 1
class Base
{
public:
virtual void foo()
{
//some work
}
};
class Derived
{
public:
virtual void foo()
{
Base::foo();
// some other work
}
};
//Méthode 2
class Base
{
private:
virtual void fooImpl() = 0;
public:
void foo()
{
//some work
fooImpl();
}
};
class Derived
{
private:
virtual void fooImpl()
{
// some other work
}
};
Methode 1 et Methode 2 ne sont pas équivalente: dans la Methode 2
fooImpl est une virtuelle pure et donc Base ne peut pas etre instanciée.
La délégation à la base dérivée fait donc partie du contrat.
L'avantage de la méthode 1 étant la simplicité, mais l'inconvénient étant
un oubli possible d'appeler Base::foo().
La seconde ayant l'avantage de ne pas pemettre l'omission de la
redéclaration de la fonction, mais est plus lourde à utiliser.
Si Derived hérite publiquement de Base, j'utilise la Méthode 2. Sinon,
ça n'a pas grande importance mais j'irai quand même aussi vers la Méthode 2.
J'ai l'impression que avec Méthode 1, il y a un plus grand risque de
violer LSP. Je ne vois pas d'exemple où j'utiliserai cette méthode (à
par pour intégrer un code dont je n'ai pas le contrôle).
je me permets de faire un post différent pour une question que j'ai posé la dernière fois.
Quelle solution vous utilisez concernant l'utilisation de méthodes virtuelles dans une classe dérivée, qui appellent la même fonction de la base:
//Méthode 1 class Base { public: virtual void foo() { //some work } };
class Derived { public: virtual void foo() { Base::foo(); // some other work } };
//Méthode 2 class Base { private: virtual void fooImpl() = 0; public: void foo() { //some work fooImpl(); } };
class Derived { private: virtual void fooImpl() { // some other work } };
Methode 1 et Methode 2 ne sont pas équivalente: dans la Methode 2 fooImpl est une virtuelle pure et donc Base ne peut pas etre instanciée. La délégation à la base dérivée fait donc partie du contrat.
L'avantage de la méthode 1 étant la simplicité, mais l'inconvénient étant un oubli possible d'appeler Base::foo().
La seconde ayant l'avantage de ne pas pemettre l'omission de la redéclaration de la fonction, mais est plus lourde à utiliser.
Si Derived hérite publiquement de Base, j'utilise la Méthode 2. Sinon, ça n'a pas grande importance mais j'irai quand même aussi vers la Méthode 2.
J'ai l'impression que avec Méthode 1, il y a un plus grand risque de violer LSP. Je ne vois pas d'exemple où j'utiliserai cette méthode (à par pour intégrer un code dont je n'ai pas le contrôle).
Michael
James Kanze
On Oct 2, 10:59 pm, DELVA Michael wrote:
je me permets de faire un post différent pour une question que j'ai pos é la dernière fois.
Quelle solution vous utilisez concernant l'utilisation de méthodes virtuelles dans une classe dérivée, qui appellent la même fonction de la base:
Je suis temté à dire que je ne le fais pas. En général, si une fonction est virtuelle dans la base, elle est aussi virtuelle pûre, sans implémentation, et ne peut donc pas être appelée.
//Méthode 1 class Base { public: virtual void foo() { //some work } };
class Derived { public: virtual void foo() { Base::foo(); // some other work } };
Dans la pratique, de tels cas me semblent bien rares.
//Méthode 2 class Base { private: virtual void fooImpl() = 0; public: void foo() { //some work fooImpl(); } };
class Derived { private: virtual void fooImpl() { // some other work } };
Ça, j'utilise souvent, mais pour d'autres raisons. Dans Base::foo(), il n'y a pas "some work", mais simplement des vérifications du contrat.
L'avantage de la méthode 1 étant la simplicité, mais l'inconvénient étant un oubli possible d'appeler Base::foo().
La seconde ayant l'avantage de ne pas pemettre l'omission de la redéclaration de la fonction, mais est plus lourde à utiliser.
Le tout dépend du but. S'il est essentiel, du point de vue de Base, que ça partie du travail ait lieu, alors, il n'y a que la deuxième solution. Si en revanche, Base fournit une implémentation partielle par commodité, que Derived peut utiliser ou non, comme il veut, je ferais probablement quelque chose du genre :
class Base { protected: void partialFoo() { /*...*/ }
public: void foo() = 0 ; } ;
(Dans de tels cas, je préfère même deux classes : une classe de base qui définit l'interface, et que l'interface, et une classe d'implémentation partielle qui en dérive. L'auteur de la classe dérivée finale peut alors choisir entre tout implémenter lui-même, en dérivant de Base, ou à se servir de l'implémentation partielle, en en dérivant.)
-- James Kanze (GABI Software) email: 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
On Oct 2, 10:59 pm, DELVA Michael <mich...@moviestats.fr> wrote:
je me permets de faire un post différent pour une question que j'ai pos é
la dernière fois.
Quelle solution vous utilisez concernant l'utilisation de méthodes
virtuelles dans une classe dérivée, qui appellent la même fonction de la
base:
Je suis temté à dire que je ne le fais pas. En général, si une
fonction est virtuelle dans la base, elle est aussi virtuelle
pûre, sans implémentation, et ne peut donc pas être appelée.
//Méthode 1
class Base
{
public:
virtual void foo()
{
//some work
}
};
class Derived
{
public:
virtual void foo()
{
Base::foo();
// some other work
}
};
Dans la pratique, de tels cas me semblent bien rares.
//Méthode 2
class Base
{
private:
virtual void fooImpl() = 0;
public:
void foo()
{
//some work
fooImpl();
}
};
class Derived
{
private:
virtual void fooImpl()
{
// some other work
}
};
Ça, j'utilise souvent, mais pour d'autres raisons. Dans
Base::foo(), il n'y a pas "some work", mais simplement des
vérifications du contrat.
L'avantage de la méthode 1 étant la simplicité, mais
l'inconvénient étant un oubli possible d'appeler Base::foo().
La seconde ayant l'avantage de ne pas pemettre l'omission de
la redéclaration de la fonction, mais est plus lourde à
utiliser.
Le tout dépend du but. S'il est essentiel, du point de vue de
Base, que ça partie du travail ait lieu, alors, il n'y a que la
deuxième solution. Si en revanche, Base fournit une
implémentation partielle par commodité, que Derived peut
utiliser ou non, comme il veut, je ferais probablement quelque
chose du genre :
class Base
{
protected:
void partialFoo() { /*...*/ }
public:
void foo() = 0 ;
} ;
(Dans de tels cas, je préfère même deux classes : une classe de
base qui définit l'interface, et que l'interface, et une classe
d'implémentation partielle qui en dérive. L'auteur de la classe
dérivée finale peut alors choisir entre tout implémenter
lui-même, en dérivant de Base, ou à se servir de
l'implémentation partielle, en en dérivant.)
--
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
je me permets de faire un post différent pour une question que j'ai pos é la dernière fois.
Quelle solution vous utilisez concernant l'utilisation de méthodes virtuelles dans une classe dérivée, qui appellent la même fonction de la base:
Je suis temté à dire que je ne le fais pas. En général, si une fonction est virtuelle dans la base, elle est aussi virtuelle pûre, sans implémentation, et ne peut donc pas être appelée.
//Méthode 1 class Base { public: virtual void foo() { //some work } };
class Derived { public: virtual void foo() { Base::foo(); // some other work } };
Dans la pratique, de tels cas me semblent bien rares.
//Méthode 2 class Base { private: virtual void fooImpl() = 0; public: void foo() { //some work fooImpl(); } };
class Derived { private: virtual void fooImpl() { // some other work } };
Ça, j'utilise souvent, mais pour d'autres raisons. Dans Base::foo(), il n'y a pas "some work", mais simplement des vérifications du contrat.
L'avantage de la méthode 1 étant la simplicité, mais l'inconvénient étant un oubli possible d'appeler Base::foo().
La seconde ayant l'avantage de ne pas pemettre l'omission de la redéclaration de la fonction, mais est plus lourde à utiliser.
Le tout dépend du but. S'il est essentiel, du point de vue de Base, que ça partie du travail ait lieu, alors, il n'y a que la deuxième solution. Si en revanche, Base fournit une implémentation partielle par commodité, que Derived peut utiliser ou non, comme il veut, je ferais probablement quelque chose du genre :
class Base { protected: void partialFoo() { /*...*/ }
public: void foo() = 0 ; } ;
(Dans de tels cas, je préfère même deux classes : une classe de base qui définit l'interface, et que l'interface, et une classe d'implémentation partielle qui en dérive. L'auteur de la classe dérivée finale peut alors choisir entre tout implémenter lui-même, en dérivant de Base, ou à se servir de l'implémentation partielle, en en dérivant.)
-- James Kanze (GABI Software) email: 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
Jean-Marc Bourguet
DELVA Michael writes:
L'avantage de la méthode 1 étant la simplicité, mais l'inconvénient étant un oubli possible d'appeler Base::foo().
La seconde ayant l'avantage de ne pas pemettre l'omission de la redéclaration de la fonction, mais est plus lourde à utiliser.
La premiere methode est aussi plus souple: dans la classe filel on peut appeler le membre de la classe de base quand on veut.
Je crois que je me baserais sur ce critere pour choisir: si cette souplesse est necessaire, la premiere methode, sinon, la deuxieme (avec vraissemblablement un nom plus significatif que simplement suffixe par Impl).
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
DELVA Michael <michael@moviestats.fr> writes:
L'avantage de la méthode 1 étant la simplicité, mais l'inconvénient étant
un oubli possible d'appeler Base::foo().
La seconde ayant l'avantage de ne pas pemettre l'omission de la
redéclaration de la fonction, mais est plus lourde à utiliser.
La premiere methode est aussi plus souple: dans la classe filel on peut
appeler le membre de la classe de base quand on veut.
Je crois que je me baserais sur ce critere pour choisir: si cette souplesse
est necessaire, la premiere methode, sinon, la deuxieme (avec
vraissemblablement un nom plus significatif que simplement suffixe par
Impl).
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
L'avantage de la méthode 1 étant la simplicité, mais l'inconvénient étant un oubli possible d'appeler Base::foo().
La seconde ayant l'avantage de ne pas pemettre l'omission de la redéclaration de la fonction, mais est plus lourde à utiliser.
La premiere methode est aussi plus souple: dans la classe filel on peut appeler le membre de la classe de base quand on veut.
Je crois que je me baserais sur ce critere pour choisir: si cette souplesse est necessaire, la premiere methode, sinon, la deuxieme (avec vraissemblablement un nom plus significatif que simplement suffixe par Impl).
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
Luc Hermitte
Salut,
On 3 oct, 09:38, Jean-Marc Bourguet wrote:
DELVA Michael writes:
L'avantage de la méthode 1 étant la simplicité, mais l'inconvén ient étant un oubli possible d'appeler Base::foo().
La seconde ayant l'avantage de ne pas pemettre l'omission de la redéclaration de la fonction, mais est plus lourde à utiliser.
La premiere methode est aussi plus souple: dans la classe fille on peut appeler le membre de la classe de base quand on veut.
Pas si souple que ça. Car on est vite prisonniers de ce schéma qui n'est valable que dans les cas où le traitement commun s'éffectue que avant, ou que après.
Sur un code existant, j'avais un fonction open() faisant des choses dans le cas général, et dans les cas spécialisés, d'autres choses devaient être réalisées avant (obligatoirement) celles du cas gén éral. Jusque là tout allait bien. Sauf que l'on avait oublié une mise à jour d'état au début de l'ouverture.
Faire ça dans la fonction mère eu été bien, sauf que ces traitements doivent être réalisés au départ, et pas après. Et faire ça dans chacune des fonctions filles pas vraiment génial.
Résultat, il fallait casser la structure courante, et retirer des fonctions dans les classes dérivées pour les remplacer par des do_pre_open-like(). C'est pas que cela soit impossible, mais quand on considère l'évolution d'un code, je n'aime vraiment pas retirer des choses, même des redéfinitions de fonctions publiques.
Bref, une très forte préférence pour l'approche façon /template- method/ qui me parait mieux respecter le principe /open-close/.
-- Luc Hermitte
Salut,
On 3 oct, 09:38, Jean-Marc Bourguet <j...@bourguet.org> wrote:
DELVA Michael <mich...@moviestats.fr> writes:
L'avantage de la méthode 1 étant la simplicité, mais l'inconvén ient étant
un oubli possible d'appeler Base::foo().
La seconde ayant l'avantage de ne pas pemettre l'omission de la
redéclaration de la fonction, mais est plus lourde à utiliser.
La premiere methode est aussi plus souple: dans la classe fille on peut
appeler le membre de la classe de base quand on veut.
Pas si souple que ça. Car on est vite prisonniers de ce schéma qui
n'est valable que dans les cas où le traitement commun s'éffectue que
avant, ou que après.
Sur un code existant, j'avais un fonction open() faisant des choses
dans le cas général, et dans les cas spécialisés, d'autres choses
devaient être réalisées avant (obligatoirement) celles du cas gén éral.
Jusque là tout allait bien. Sauf que l'on avait oublié une mise à jour
d'état au début de l'ouverture.
Faire ça dans la fonction mère eu été bien, sauf que ces traitements
doivent être réalisés au départ, et pas après. Et faire ça dans
chacune des fonctions filles pas vraiment génial.
Résultat, il fallait casser la structure courante, et retirer des
fonctions dans les classes dérivées pour les remplacer par des
do_pre_open-like(). C'est pas que cela soit impossible, mais quand on
considère l'évolution d'un code, je n'aime vraiment pas retirer des
choses, même des redéfinitions de fonctions publiques.
Bref, une très forte préférence pour l'approche façon /template-
method/ qui me parait mieux respecter le principe /open-close/.
L'avantage de la méthode 1 étant la simplicité, mais l'inconvén ient étant un oubli possible d'appeler Base::foo().
La seconde ayant l'avantage de ne pas pemettre l'omission de la redéclaration de la fonction, mais est plus lourde à utiliser.
La premiere methode est aussi plus souple: dans la classe fille on peut appeler le membre de la classe de base quand on veut.
Pas si souple que ça. Car on est vite prisonniers de ce schéma qui n'est valable que dans les cas où le traitement commun s'éffectue que avant, ou que après.
Sur un code existant, j'avais un fonction open() faisant des choses dans le cas général, et dans les cas spécialisés, d'autres choses devaient être réalisées avant (obligatoirement) celles du cas gén éral. Jusque là tout allait bien. Sauf que l'on avait oublié une mise à jour d'état au début de l'ouverture.
Faire ça dans la fonction mère eu été bien, sauf que ces traitements doivent être réalisés au départ, et pas après. Et faire ça dans chacune des fonctions filles pas vraiment génial.
Résultat, il fallait casser la structure courante, et retirer des fonctions dans les classes dérivées pour les remplacer par des do_pre_open-like(). C'est pas que cela soit impossible, mais quand on considère l'évolution d'un code, je n'aime vraiment pas retirer des choses, même des redéfinitions de fonctions publiques.
Bref, une très forte préférence pour l'approche façon /template- method/ qui me parait mieux respecter le principe /open-close/.