Bonjour à tous,
Je viens de réaliser qu'il était possible de faire de l'héritage entre
inner classes. Il y a même pleins de possibilités:
class A
{
public:
class PublicInnerA {};
protected:
class ProtectedInnerA {};
};
class B : public A::PublicInnerA {};
class C : public A
{
class InnerC;
};
class C::InnerC : public A::ProtectedInnerA
{
};
je trouve ce procédé génial, je vais m'efforcer d'entre trouver une
utilité ;-)
Plus sérieusement, je ne l'ai jamais croisé, et m'en étonne. N'y a-t-il
pas de technique particulière qui l'utilise ? Un cas typique où ça se
révèle une solution élégante ?
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
Fabien LE LEZ
On Thu, 02 Feb 2006 14:03:59 +0100, Aurelien Regat-Barrel :
je trouve ce procédé génial, je vais m'efforcer d'entre trouver une utilité ;-)
Barf... Une classe est une classe, qu'elle soit membre d'une autre classe ou pas. En pratique, s'il s'agit d'isoler des classes, les mettre dans un namespace dédié est une solution au moins aussi fréquente (du moins dans mon code) que les mettre comme classes membres.
On Thu, 02 Feb 2006 14:03:59 +0100, Aurelien Regat-Barrel
<nospam.aregatba@yahoo.fr>:
je trouve ce procédé génial, je vais m'efforcer d'entre trouver une
utilité ;-)
Barf... Une classe est une classe, qu'elle soit membre d'une autre
classe ou pas.
En pratique, s'il s'agit d'isoler des classes, les mettre dans un
namespace dédié est une solution au moins aussi fréquente (du moins
dans mon code) que les mettre comme classes membres.
On Thu, 02 Feb 2006 14:03:59 +0100, Aurelien Regat-Barrel :
je trouve ce procédé génial, je vais m'efforcer d'entre trouver une utilité ;-)
Barf... Une classe est une classe, qu'elle soit membre d'une autre classe ou pas. En pratique, s'il s'agit d'isoler des classes, les mettre dans un namespace dédié est une solution au moins aussi fréquente (du moins dans mon code) que les mettre comme classes membres.
Jean-Sebastien Mouret
Aurelien Regat-Barrel writes:
Bonjour à tous, Je viens de réaliser qu'il était possible de faire de l'héritage entre inner classes. Il y a même pleins de possibilités:
[pleins de possibilités]
je trouve ce procédé génial, je vais m'efforcer d'entre trouver une utilité ;-) Plus sérieusement, je ne l'ai jamais croisé, et m'en étonne. N'y a-t-il pas de technique particulière qui l'utilise ? Un cas typique où ça se révèle une solution élégante ?
Les traits sont un exemple de ce genre de construction, sauf que l'on utilise plutôt des typedefs, ce qui revient au même.
Un exemple sympa serait une classe container avec la définition de son itérateur à l'intérieur même de celle du container.
typedef<typename T> class container { class iterator { //...
Bonjour à tous,
Je viens de réaliser qu'il était possible de faire de l'héritage entre
inner classes. Il y a même pleins de possibilités:
[pleins de possibilités]
je trouve ce procédé génial, je vais m'efforcer d'entre trouver une
utilité ;-)
Plus sérieusement, je ne l'ai jamais croisé, et m'en étonne. N'y a-t-il
pas de technique particulière qui l'utilise ? Un cas typique où ça se
révèle une solution élégante ?
Les traits sont un exemple de ce genre de construction,
sauf que l'on utilise plutôt des typedefs, ce qui revient au même.
Un exemple sympa serait une classe container avec la définition
de son itérateur à l'intérieur même de celle du container.
typedef<typename T>
class container
{
class iterator
{
//...
Bonjour à tous, Je viens de réaliser qu'il était possible de faire de l'héritage entre inner classes. Il y a même pleins de possibilités:
[pleins de possibilités]
je trouve ce procédé génial, je vais m'efforcer d'entre trouver une utilité ;-) Plus sérieusement, je ne l'ai jamais croisé, et m'en étonne. N'y a-t-il pas de technique particulière qui l'utilise ? Un cas typique où ça se révèle une solution élégante ?
Les traits sont un exemple de ce genre de construction, sauf que l'on utilise plutôt des typedefs, ce qui revient au même.
Un exemple sympa serait une classe container avec la définition de son itérateur à l'intérieur même de celle du container.
typedef<typename T> class container { class iterator { //...
-- js
kanze
Aurelien Regat-Barrel wrote:
Je viens de réaliser qu'il était possible de faire de l'héritage entre inner classes.
Une première remarque : j'éviterais le vocable « inner class ». En C++, on parle d'habitude des « nested class », ou en français, des classes embriquées. Et le C++ n'a rien qui ressemble aux « inner class » de Java. (En Java, un « inner class », c'est un « nested class » qui contient une référence implicite à un objet de la classe qui le contient -- on ne peut en créer une instance que dans une fonction membre non-statique de la classe, où on a un pointeur this pour initialiser cette référence. Rien à voir, donc, avec les classes imbriquées du C++, ni même avec les autres classes imbriquées de Java.)
Il y a même pleins de possibilités:
class A { public: class PublicInnerA {}; protected: class ProtectedInnerA {}; };
class B : public A::PublicInnerA {};
class C : public A { class InnerC; };
class C::InnerC : public A::ProtectedInnerA { };
je trouve ce procédé génial, je vais m'efforcer d'entre trouver une utilité ;-)
Je dirais que c'est assez fréquent, même. Je ne crois pas avoir fait une application qui ne s'en servait pas.
Je l'utilise beaucoup aussi dans des classes templatées un peu complexe, de peu que la classe en question utilise des noeuds ou d'autres classes « implémentation ». Il y a une classe de base non templatée qui factorise la partie vraiment générique (c-à-d qui ne dépend pas des paramètres d'instantiation du template). Donc, par exemple, j'ai une classe :
class HashTableImpl { // ... protected: class Node { // ... } ; } ;
template< typename T > class AssocArrayOf : public HashTableImpl { // ... struct TypedNode : Node { T value ; // ... } ; } ;
(Dans ce cas-ci, HashTableImpl contient toute la gestion du table haché, mais compte sur la classe dérivée pour les opérations qui dépend du type, comme calculer le hachage, comparer deux valeurs pour égalité, ou créer et detruire les noeuds.)
Plus sérieusement, je ne l'ai jamais croisé, et m'en étonne.
C'est cependant une technique fréquente -- dans l'implémentation des templates, pour éviter le code bloat, comme ci-dessus, mais aussi pour des cas comme les Visitor, ou les Actions dans une transaction.
N'y a-t-il pas de technique particulière qui l'utilise ? Un cas typique où ça se révèle une solution élégante ?
Voir ci-dessus. Aussi le modèle visiteur :
class Visitable { public : class Visitor { public: virtual ~Visitor() {} virtual void doSomething( Visitable& obj ) = 0 ; } ; // ... } ;
Aussi pour les actions associées à une transaction. Ou pour les Undo. (Selon la façon qu'on gère les transactions.)
-- James Kanze GABI Software 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
Aurelien Regat-Barrel wrote:
Je viens de réaliser qu'il était possible de faire de
l'héritage entre inner classes.
Une première remarque : j'éviterais le vocable « inner class ».
En C++, on parle d'habitude des « nested class », ou en
français, des classes embriquées. Et le C++ n'a rien qui
ressemble aux « inner class » de Java. (En Java, un « inner
class », c'est un « nested class » qui contient une référence
implicite à un objet de la classe qui le contient -- on ne peut
en créer une instance que dans une fonction membre non-statique
de la classe, où on a un pointeur this pour initialiser cette
référence. Rien à voir, donc, avec les classes imbriquées du
C++, ni même avec les autres classes imbriquées de Java.)
Il y a même pleins de
possibilités:
class A
{
public:
class PublicInnerA {};
protected:
class ProtectedInnerA {};
};
class B : public A::PublicInnerA {};
class C : public A
{
class InnerC;
};
class C::InnerC : public A::ProtectedInnerA
{
};
je trouve ce procédé génial, je vais m'efforcer d'entre
trouver une utilité ;-)
Je dirais que c'est assez fréquent, même. Je ne crois pas avoir
fait une application qui ne s'en servait pas.
Je l'utilise beaucoup aussi dans des classes templatées un peu
complexe, de peu que la classe en question utilise des noeuds ou
d'autres classes « implémentation ». Il y a une classe de base
non templatée qui factorise la partie vraiment générique (c-à-d
qui ne dépend pas des paramètres d'instantiation du template).
Donc, par exemple, j'ai une classe :
class HashTableImpl
{
// ...
protected:
class Node
{
// ...
} ;
} ;
template< typename T >
class AssocArrayOf : public HashTableImpl
{
// ...
struct TypedNode : Node
{
T value ;
// ...
} ;
} ;
(Dans ce cas-ci, HashTableImpl contient toute la gestion du
table haché, mais compte sur la classe dérivée pour les
opérations qui dépend du type, comme calculer le hachage,
comparer deux valeurs pour égalité, ou créer et detruire les
noeuds.)
Plus sérieusement, je ne l'ai jamais croisé, et m'en étonne.
C'est cependant une technique fréquente -- dans l'implémentation
des templates, pour éviter le code bloat, comme ci-dessus, mais
aussi pour des cas comme les Visitor, ou les Actions dans une
transaction.
N'y a-t-il pas de technique particulière qui l'utilise ? Un
cas typique où ça se révèle une solution élégante ?
Voir ci-dessus. Aussi le modèle visiteur :
class Visitable
{
public :
class Visitor
{
public:
virtual ~Visitor() {}
virtual void doSomething( Visitable& obj ) = 0 ;
} ;
// ...
} ;
Aussi pour les actions associées à une transaction. Ou pour les
Undo. (Selon la façon qu'on gère les transactions.)
--
James Kanze GABI Software
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 viens de réaliser qu'il était possible de faire de l'héritage entre inner classes.
Une première remarque : j'éviterais le vocable « inner class ». En C++, on parle d'habitude des « nested class », ou en français, des classes embriquées. Et le C++ n'a rien qui ressemble aux « inner class » de Java. (En Java, un « inner class », c'est un « nested class » qui contient une référence implicite à un objet de la classe qui le contient -- on ne peut en créer une instance que dans une fonction membre non-statique de la classe, où on a un pointeur this pour initialiser cette référence. Rien à voir, donc, avec les classes imbriquées du C++, ni même avec les autres classes imbriquées de Java.)
Il y a même pleins de possibilités:
class A { public: class PublicInnerA {}; protected: class ProtectedInnerA {}; };
class B : public A::PublicInnerA {};
class C : public A { class InnerC; };
class C::InnerC : public A::ProtectedInnerA { };
je trouve ce procédé génial, je vais m'efforcer d'entre trouver une utilité ;-)
Je dirais que c'est assez fréquent, même. Je ne crois pas avoir fait une application qui ne s'en servait pas.
Je l'utilise beaucoup aussi dans des classes templatées un peu complexe, de peu que la classe en question utilise des noeuds ou d'autres classes « implémentation ». Il y a une classe de base non templatée qui factorise la partie vraiment générique (c-à-d qui ne dépend pas des paramètres d'instantiation du template). Donc, par exemple, j'ai une classe :
class HashTableImpl { // ... protected: class Node { // ... } ; } ;
template< typename T > class AssocArrayOf : public HashTableImpl { // ... struct TypedNode : Node { T value ; // ... } ; } ;
(Dans ce cas-ci, HashTableImpl contient toute la gestion du table haché, mais compte sur la classe dérivée pour les opérations qui dépend du type, comme calculer le hachage, comparer deux valeurs pour égalité, ou créer et detruire les noeuds.)
Plus sérieusement, je ne l'ai jamais croisé, et m'en étonne.
C'est cependant une technique fréquente -- dans l'implémentation des templates, pour éviter le code bloat, comme ci-dessus, mais aussi pour des cas comme les Visitor, ou les Actions dans une transaction.
N'y a-t-il pas de technique particulière qui l'utilise ? Un cas typique où ça se révèle une solution élégante ?
Voir ci-dessus. Aussi le modèle visiteur :
class Visitable { public : class Visitor { public: virtual ~Visitor() {} virtual void doSomething( Visitable& obj ) = 0 ; } ; // ... } ;
Aussi pour les actions associées à une transaction. Ou pour les Undo. (Selon la façon qu'on gère les transactions.)
-- James Kanze GABI Software 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
Aurelien Regat-Barrel
je trouve ce procédé génial, je vais m'efforcer d'entre trouver une utilité ;-)
Je dirais que c'est assez fréquent, même. Je ne crois pas avoir fait une application qui ne s'en servait pas.
Je l'utilise beaucoup aussi dans des classes templatées un peu complexe, de peu que la classe en question utilise des noeuds ou d'autres classes « implémentation ». Il y a une classe de base non templatée qui factorise la partie vraiment générique (c-à-d qui ne dépend pas des paramètres d'instantiation du template). Donc, par exemple, j'ai une classe :
class HashTableImpl { // ... protected: class Node { // ... } ; } ;
template< typename T > class AssocArrayOf : public HashTableImpl { // ... struct TypedNode : Node { T value ; // ... } ; } ;
(Dans ce cas-ci, HashTableImpl contient toute la gestion du table haché, mais compte sur la classe dérivée pour les opérations qui dépend du type, comme calculer le hachage, comparer deux valeurs pour égalité, ou créer et detruire les noeuds.)
Plus sérieusement, je ne l'ai jamais croisé, et m'en étonne.
C'est cependant une technique fréquente -- dans l'implémentation des templates, pour éviter le code bloat, comme ci-dessus, mais aussi pour des cas comme les Visitor, ou les Actions dans une transaction.
Ah dans les templates peut être. En fait ce procédé me fait penser à la technique du pimpl, mais où le pimpl serait implémenté par les classes filles. C'est de la paramétrisation de classe mère en quelque sorte, comme les templates, sauf qu'il y a une classe mère commune, et que c'est pas "ouvert" (choix du paramètre par l'utilisateur). Bref, une manière de factoriser du code, sans template.
Je l'ai dit, je m'efforce d'en trouver une utilité. Mais typiquement, j'ai déjà écrit ce genre de code (en simplifié toujours):
class Base { public: int DoSomething() { return this->GetSomething1() + this->GetSomething2(); }
protected: virtual int GetSomething1() = 0; virtual int GetSomething2() = 0; };
Isoler l'interface à implémenter dans une nested class ne serait-il pas plus élégant ?
class Base { protected: class BaseInterface { public: virtual int GetSomething1() = 0; virtual int GetSomething2() = 0; };
public: int DoSomething() { return i_->GetSomething1() + i_->GetSomething2(); }
protected: Base( BaseInterface *I ) : i_( I ) {}
private: BaseInterface *i_; };
-- Aurélien Regat-Barrel
je trouve ce procédé génial, je vais m'efforcer d'entre
trouver une utilité ;-)
Je dirais que c'est assez fréquent, même. Je ne crois pas avoir
fait une application qui ne s'en servait pas.
Je l'utilise beaucoup aussi dans des classes templatées un peu
complexe, de peu que la classe en question utilise des noeuds ou
d'autres classes « implémentation ». Il y a une classe de base
non templatée qui factorise la partie vraiment générique (c-à-d
qui ne dépend pas des paramètres d'instantiation du template).
Donc, par exemple, j'ai une classe :
class HashTableImpl
{
// ...
protected:
class Node
{
// ...
} ;
} ;
template< typename T >
class AssocArrayOf : public HashTableImpl
{
// ...
struct TypedNode : Node
{
T value ;
// ...
} ;
} ;
(Dans ce cas-ci, HashTableImpl contient toute la gestion du
table haché, mais compte sur la classe dérivée pour les
opérations qui dépend du type, comme calculer le hachage,
comparer deux valeurs pour égalité, ou créer et detruire les
noeuds.)
Plus sérieusement, je ne l'ai jamais croisé, et m'en étonne.
C'est cependant une technique fréquente -- dans l'implémentation
des templates, pour éviter le code bloat, comme ci-dessus, mais
aussi pour des cas comme les Visitor, ou les Actions dans une
transaction.
Ah dans les templates peut être. En fait ce procédé me fait penser à la
technique du pimpl, mais où le pimpl serait implémenté par les classes
filles. C'est de la paramétrisation de classe mère en quelque sorte,
comme les templates, sauf qu'il y a une classe mère commune, et que
c'est pas "ouvert" (choix du paramètre par l'utilisateur).
Bref, une manière de factoriser du code, sans template.
Je l'ai dit, je m'efforce d'en trouver une utilité. Mais typiquement,
j'ai déjà écrit ce genre de code (en simplifié toujours):
class Base
{
public:
int DoSomething()
{
return this->GetSomething1() + this->GetSomething2();
}
protected:
virtual int GetSomething1() = 0;
virtual int GetSomething2() = 0;
};
Isoler l'interface à implémenter dans une nested class ne serait-il pas
plus élégant ?
class Base
{
protected:
class BaseInterface
{
public:
virtual int GetSomething1() = 0;
virtual int GetSomething2() = 0;
};
public:
int DoSomething()
{
return i_->GetSomething1() + i_->GetSomething2();
}
je trouve ce procédé génial, je vais m'efforcer d'entre trouver une utilité ;-)
Je dirais que c'est assez fréquent, même. Je ne crois pas avoir fait une application qui ne s'en servait pas.
Je l'utilise beaucoup aussi dans des classes templatées un peu complexe, de peu que la classe en question utilise des noeuds ou d'autres classes « implémentation ». Il y a une classe de base non templatée qui factorise la partie vraiment générique (c-à-d qui ne dépend pas des paramètres d'instantiation du template). Donc, par exemple, j'ai une classe :
class HashTableImpl { // ... protected: class Node { // ... } ; } ;
template< typename T > class AssocArrayOf : public HashTableImpl { // ... struct TypedNode : Node { T value ; // ... } ; } ;
(Dans ce cas-ci, HashTableImpl contient toute la gestion du table haché, mais compte sur la classe dérivée pour les opérations qui dépend du type, comme calculer le hachage, comparer deux valeurs pour égalité, ou créer et detruire les noeuds.)
Plus sérieusement, je ne l'ai jamais croisé, et m'en étonne.
C'est cependant une technique fréquente -- dans l'implémentation des templates, pour éviter le code bloat, comme ci-dessus, mais aussi pour des cas comme les Visitor, ou les Actions dans une transaction.
Ah dans les templates peut être. En fait ce procédé me fait penser à la technique du pimpl, mais où le pimpl serait implémenté par les classes filles. C'est de la paramétrisation de classe mère en quelque sorte, comme les templates, sauf qu'il y a une classe mère commune, et que c'est pas "ouvert" (choix du paramètre par l'utilisateur). Bref, une manière de factoriser du code, sans template.
Je l'ai dit, je m'efforce d'en trouver une utilité. Mais typiquement, j'ai déjà écrit ce genre de code (en simplifié toujours):
class Base { public: int DoSomething() { return this->GetSomething1() + this->GetSomething2(); }
protected: virtual int GetSomething1() = 0; virtual int GetSomething2() = 0; };
Isoler l'interface à implémenter dans une nested class ne serait-il pas plus élégant ?
class Base { protected: class BaseInterface { public: virtual int GetSomething1() = 0; virtual int GetSomething2() = 0; };
public: int DoSomething() { return i_->GetSomething1() + i_->GetSomething2(); }
protected: Base( BaseInterface *I ) : i_( I ) {}
private: BaseInterface *i_; };
-- Aurélien Regat-Barrel
Aurelien Regat-Barrel
J'avais fait un longue réponse mais je comprends pas j'ai du faire une fausse manip elle semble s'être perdu :-(
je trouve ce procédé génial, je vais m'efforcer d'entre trouver une utilité ;-)
Barf... Une classe est une classe, qu'elle soit membre d'une autre classe ou pas.
La grande différence je trouve c'est que si la nested class est protected on peut restreindre son héritage, qui doit passer par un héritage de la classe "racine". Dans le cas de 2 classes fortement couplées, ça me parrait intéressant. En particulier pour des hiérarchies d'héritage double. Par exemple, une classe Object et ObjectID. J'aurai eu tendance à faire:
class ObjectID { public: vitual ~ObjectID() = 0; };
class Object { public: virtual ObjectID* GetID() = 0; };
ObjectID n'a rien à faire seul, il n'a de sens qu'avec Object. Les regrouper ensembles me semble meilleur:
class Object { protected: class ObjectID { public: vitual ~ObjectID() = 0; };
public: virtual ObjectID* GetID() = 0; };
On peut parfaitement utiliser ObjectID, mais on ne peut pas en hériter directement : il faut aussi spécialiser Object. C'est un héritage conditionnel en quelque sorte. Ca me parrait une possibilité intéressante, mais je n'en voit pas trop le champ d'application.
En pratique, s'il s'agit d'isoler des classes, les mettre dans un namespace dédié est une solution au moins aussi fréquente (du moins dans mon code) que les mettre comme classes membres.
-- Aurélien Regat-Barrel
J'avais fait un longue réponse mais je comprends pas j'ai du faire une
fausse manip elle semble s'être perdu :-(
je trouve ce procédé génial, je vais m'efforcer d'entre trouver une
utilité ;-)
Barf... Une classe est une classe, qu'elle soit membre d'une autre
classe ou pas.
La grande différence je trouve c'est que si la nested class est
protected on peut restreindre son héritage, qui doit passer par un
héritage de la classe "racine".
Dans le cas de 2 classes fortement couplées, ça me parrait intéressant.
En particulier pour des hiérarchies d'héritage double. Par exemple, une
classe Object et ObjectID. J'aurai eu tendance à faire:
class ObjectID
{
public:
vitual ~ObjectID() = 0;
};
class Object
{
public:
virtual ObjectID* GetID() = 0;
};
ObjectID n'a rien à faire seul, il n'a de sens qu'avec Object. Les
regrouper ensembles me semble meilleur:
class Object
{
protected:
class ObjectID { public: vitual ~ObjectID() = 0; };
public:
virtual ObjectID* GetID() = 0;
};
On peut parfaitement utiliser ObjectID, mais on ne peut pas en hériter
directement : il faut aussi spécialiser Object. C'est un héritage
conditionnel en quelque sorte.
Ca me parrait une possibilité intéressante, mais je n'en voit pas trop
le champ d'application.
En pratique, s'il s'agit d'isoler des classes, les mettre dans un
namespace dédié est une solution au moins aussi fréquente (du moins
dans mon code) que les mettre comme classes membres.
J'avais fait un longue réponse mais je comprends pas j'ai du faire une fausse manip elle semble s'être perdu :-(
je trouve ce procédé génial, je vais m'efforcer d'entre trouver une utilité ;-)
Barf... Une classe est une classe, qu'elle soit membre d'une autre classe ou pas.
La grande différence je trouve c'est que si la nested class est protected on peut restreindre son héritage, qui doit passer par un héritage de la classe "racine". Dans le cas de 2 classes fortement couplées, ça me parrait intéressant. En particulier pour des hiérarchies d'héritage double. Par exemple, une classe Object et ObjectID. J'aurai eu tendance à faire:
class ObjectID { public: vitual ~ObjectID() = 0; };
class Object { public: virtual ObjectID* GetID() = 0; };
ObjectID n'a rien à faire seul, il n'a de sens qu'avec Object. Les regrouper ensembles me semble meilleur:
class Object { protected: class ObjectID { public: vitual ~ObjectID() = 0; };
public: virtual ObjectID* GetID() = 0; };
On peut parfaitement utiliser ObjectID, mais on ne peut pas en hériter directement : il faut aussi spécialiser Object. C'est un héritage conditionnel en quelque sorte. Ca me parrait une possibilité intéressante, mais je n'en voit pas trop le champ d'application.
En pratique, s'il s'agit d'isoler des classes, les mettre dans un namespace dédié est une solution au moins aussi fréquente (du moins dans mon code) que les mettre comme classes membres.
-- Aurélien Regat-Barrel
kanze
Aurelien Regat-Barrel wrote:
[...]
Je l'ai dit, je m'efforce d'en trouver une utilité. Mais typiquement, j'ai déjà écrit ce genre de code (en simplifié toujours):
class Base { public: int DoSomething() { return this->GetSomething1() + this->GetSomething2(); }
protected: virtual int GetSomething1() = 0; virtual int GetSomething2() = 0; };
Isoler l'interface à implémenter dans une nested class ne serait-il p as plus élégant ?
class Base { protected: class BaseInterface { public: virtual int GetSomething1() = 0; virtual int GetSomething2() = 0; };
public: int DoSomething() { return i_->GetSomething1() + i_->GetSomething2(); }
protected: Base( BaseInterface *I ) : i_( I ) {}
private: BaseInterface *i_; };
Modèle de template, contre modèle de stratégie. En général, je préfère le modèle de stratégie, mais ce n'est pas une règle absolue. Le modèle de template sert surtout quand tu as de bons défauts, et donc une implémentation dans la classe de base. Dans ces cas-là, souvent, on peut utiliser la classe de base sans en dériver ; on n'en dérive que pour modifier le comportement de base. (Ça arrive souvent dans les hiérarchies de GUI.)
Si tu veux utiliser le polymorphisme dans le constructeur, il n'y a que le modèle de stratégie qui marche. Et encore, il faut faire gaffe à l'ordre d'initialisation, au moins que tu exiges que la classe déléguée soit allouée dynamiquement, et libérée dans le destructeur de la Base. (Dans ce cas-là, je suggèrerais l'utilisation de std::auto_ptr, déjà comme paramètre au constructeur de la classe de base.)
-- James Kanze GABI Software 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
Aurelien Regat-Barrel wrote:
[...]
Je l'ai dit, je m'efforce d'en trouver une utilité. Mais
typiquement, j'ai déjà écrit ce genre de code (en simplifié
toujours):
class Base
{
public:
int DoSomething()
{
return this->GetSomething1() + this->GetSomething2();
}
protected:
virtual int GetSomething1() = 0;
virtual int GetSomething2() = 0;
};
Isoler l'interface à implémenter dans une nested class ne serait-il p as
plus élégant ?
class Base
{
protected:
class BaseInterface
{
public:
virtual int GetSomething1() = 0;
virtual int GetSomething2() = 0;
};
public:
int DoSomething()
{
return i_->GetSomething1() + i_->GetSomething2();
}
protected:
Base( BaseInterface *I ) : i_( I ) {}
private:
BaseInterface *i_;
};
Modèle de template, contre modèle de stratégie. En général, je
préfère le modèle de stratégie, mais ce n'est pas une règle
absolue. Le modèle de template sert surtout quand tu as de bons
défauts, et donc une implémentation dans la classe de base.
Dans ces cas-là, souvent, on peut utiliser la classe de base
sans en dériver ; on n'en dérive que pour modifier le
comportement de base. (Ça arrive souvent dans les hiérarchies de
GUI.)
Si tu veux utiliser le polymorphisme dans le constructeur, il
n'y a que le modèle de stratégie qui marche. Et encore, il faut
faire gaffe à l'ordre d'initialisation, au moins que tu exiges
que la classe déléguée soit allouée dynamiquement, et libérée
dans le destructeur de la Base. (Dans ce cas-là, je suggèrerais
l'utilisation de std::auto_ptr, déjà comme paramètre au
constructeur de la classe de base.)
--
James Kanze GABI Software
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 l'ai dit, je m'efforce d'en trouver une utilité. Mais typiquement, j'ai déjà écrit ce genre de code (en simplifié toujours):
class Base { public: int DoSomething() { return this->GetSomething1() + this->GetSomething2(); }
protected: virtual int GetSomething1() = 0; virtual int GetSomething2() = 0; };
Isoler l'interface à implémenter dans une nested class ne serait-il p as plus élégant ?
class Base { protected: class BaseInterface { public: virtual int GetSomething1() = 0; virtual int GetSomething2() = 0; };
public: int DoSomething() { return i_->GetSomething1() + i_->GetSomething2(); }
protected: Base( BaseInterface *I ) : i_( I ) {}
private: BaseInterface *i_; };
Modèle de template, contre modèle de stratégie. En général, je préfère le modèle de stratégie, mais ce n'est pas une règle absolue. Le modèle de template sert surtout quand tu as de bons défauts, et donc une implémentation dans la classe de base. Dans ces cas-là, souvent, on peut utiliser la classe de base sans en dériver ; on n'en dérive que pour modifier le comportement de base. (Ça arrive souvent dans les hiérarchies de GUI.)
Si tu veux utiliser le polymorphisme dans le constructeur, il n'y a que le modèle de stratégie qui marche. Et encore, il faut faire gaffe à l'ordre d'initialisation, au moins que tu exiges que la classe déléguée soit allouée dynamiquement, et libérée dans le destructeur de la Base. (Dans ce cas-là, je suggèrerais l'utilisation de std::auto_ptr, déjà comme paramètre au constructeur de la classe de base.)
-- James Kanze GABI Software 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
Aurelien Regat-Barrel
Modèle de template, contre modèle de stratégie. En général, je préfère le modèle de stratégie, mais ce n'est pas une règle absolue. Le modèle de template sert surtout quand tu as de bons défauts, et donc une implémentation dans la classe de base. Dans ces cas-là, souvent, on peut utiliser la classe de base sans en dériver ; on n'en dérive que pour modifier le comportement de base. (Ça arrive souvent dans les hiérarchies de GUI.)
Si tu veux utiliser le polymorphisme dans le constructeur, il n'y a que le modèle de stratégie qui marche. Et encore, il faut faire gaffe à l'ordre d'initialisation, au moins que tu exiges que la classe déléguée soit allouée dynamiquement, et libérée dans le destructeur de la Base. (Dans ce cas-là, je suggèrerais l'utilisation de std::auto_ptr, déjà comme paramètre au constructeur de la classe de base.)
D'accord. Merci pour ces précisions.
-- Aurélien Regat-Barrel
Modèle de template, contre modèle de stratégie. En général, je
préfère le modèle de stratégie, mais ce n'est pas une règle
absolue. Le modèle de template sert surtout quand tu as de bons
défauts, et donc une implémentation dans la classe de base.
Dans ces cas-là, souvent, on peut utiliser la classe de base
sans en dériver ; on n'en dérive que pour modifier le
comportement de base. (Ça arrive souvent dans les hiérarchies de
GUI.)
Si tu veux utiliser le polymorphisme dans le constructeur, il
n'y a que le modèle de stratégie qui marche. Et encore, il faut
faire gaffe à l'ordre d'initialisation, au moins que tu exiges
que la classe déléguée soit allouée dynamiquement, et libérée
dans le destructeur de la Base. (Dans ce cas-là, je suggèrerais
l'utilisation de std::auto_ptr, déjà comme paramètre au
constructeur de la classe de base.)
Modèle de template, contre modèle de stratégie. En général, je préfère le modèle de stratégie, mais ce n'est pas une règle absolue. Le modèle de template sert surtout quand tu as de bons défauts, et donc une implémentation dans la classe de base. Dans ces cas-là, souvent, on peut utiliser la classe de base sans en dériver ; on n'en dérive que pour modifier le comportement de base. (Ça arrive souvent dans les hiérarchies de GUI.)
Si tu veux utiliser le polymorphisme dans le constructeur, il n'y a que le modèle de stratégie qui marche. Et encore, il faut faire gaffe à l'ordre d'initialisation, au moins que tu exiges que la classe déléguée soit allouée dynamiquement, et libérée dans le destructeur de la Base. (Dans ce cas-là, je suggèrerais l'utilisation de std::auto_ptr, déjà comme paramètre au constructeur de la classe de base.)
D'accord. Merci pour ces précisions.
-- Aurélien Regat-Barrel
Luc Hermitte
Bonsoir,
Aurelien Regat-Barrel wrote in news:43e20366$0 $282$:
Je viens de réaliser qu'il était possible de faire de l'héritage entre inner classes. Il y a même pleins de possibilités: [...] je trouve ce procédé génial, je vais m'efforcer d'entre trouver une utilité ;-) Plus sérieusement, je ne l'ai jamais croisé, et m'en étonne. N'y a-t-il pas de technique particulière qui l'utilise ? Un cas typique où ça se révèle une solution élégante ?
Comme ça, je pense aux mixin-layers (assimilables à du CRTP en couches) au sujet desquels Smaragdakis a écrit une thèse, en 99, disponible sur le net.
-- Luc Hermitte <hermitte at free.fr> FAQ de <news:fr.comp.lang.c++> : <http://www.cmla.ens-cachan.fr/Utilisateurs/dosreis/C++/FAQ/> Dejanews : <http://groups.google.com/advanced_group_search>
Bonsoir,
Aurelien Regat-Barrel <nospam.aregatba@yahoo.fr> wrote in news:43e20366$0
$282$626a14ce@news.free.fr:
Je viens de réaliser qu'il était possible de faire de l'héritage entre
inner classes. Il y a même pleins de possibilités:
[...]
je trouve ce procédé génial, je vais m'efforcer d'entre trouver une
utilité ;-)
Plus sérieusement, je ne l'ai jamais croisé, et m'en étonne. N'y a-t-il
pas de technique particulière qui l'utilise ? Un cas typique où ça se
révèle une solution élégante ?
Comme ça, je pense aux mixin-layers (assimilables à du CRTP en couches) au
sujet desquels Smaragdakis a écrit une thèse, en 99, disponible sur le net.
--
Luc Hermitte <hermitte at free.fr>
FAQ de <news:fr.comp.lang.c++> :
<http://www.cmla.ens-cachan.fr/Utilisateurs/dosreis/C++/FAQ/>
Dejanews : <http://groups.google.com/advanced_group_search>
Aurelien Regat-Barrel wrote in news:43e20366$0 $282$:
Je viens de réaliser qu'il était possible de faire de l'héritage entre inner classes. Il y a même pleins de possibilités: [...] je trouve ce procédé génial, je vais m'efforcer d'entre trouver une utilité ;-) Plus sérieusement, je ne l'ai jamais croisé, et m'en étonne. N'y a-t-il pas de technique particulière qui l'utilise ? Un cas typique où ça se révèle une solution élégante ?
Comme ça, je pense aux mixin-layers (assimilables à du CRTP en couches) au sujet desquels Smaragdakis a écrit une thèse, en 99, disponible sur le net.
-- Luc Hermitte <hermitte at free.fr> FAQ de <news:fr.comp.lang.c++> : <http://www.cmla.ens-cachan.fr/Utilisateurs/dosreis/C++/FAQ/> Dejanews : <http://groups.google.com/advanced_group_search>
Aurelien Regat-Barrel
Comme ça, je pense aux mixin-layers (assimilables à du CRTP en couches) au sujet desquels Smaragdakis a écrit une thèse, en 99, disponible sur le net.
Je crois que j'avais imprimé un long papier sur le sujet, mais j'ai pas eu le cran pour m'y atteler... Je vais m'y repencher à l'occasion. Merci.
-- Aurélien Regat-Barrel
Comme ça, je pense aux mixin-layers (assimilables à du CRTP en couches) au
sujet desquels Smaragdakis a écrit une thèse, en 99, disponible sur le net.
Je crois que j'avais imprimé un long papier sur le sujet, mais j'ai pas
eu le cran pour m'y atteler... Je vais m'y repencher à l'occasion.
Merci.