if (toto != NULL) toto = *ITE, Ce code est inutile.
deriv1 * toto = dynamic_cast<deriv1*>(*ITE); Je pense que tu veux parler de conversion et non de copy (convertir la
classe de base vers la classe dérivée appelée aussi downcasting) Si tu veux éviter les if/else ,il faut utiliser des méthode virtuelles.
Ahmed
"Michael" wrote in message news:
Bonjour à tous,
soient les classes suivantes:
class base //(classe abstraite) { // blabla };
class deriv1 : public base { //blabla };
class deriv2 : public base { //blabla };
Soit:
std::vector<base*> liste;
Si je prends un iterator quelconque:
std::vector<base*>::const_iterator ITE = ...;
je voudrais faire une copie de ce que contient cet iterateur...
Seulement comment faire ça? est-ce que je dois tester quelque chose du type:
deriv1 * toto = dynamic_cast<deriv1*>(*ITE); if (toto != NULL) toto = *ITE, else { deriv2 * foo = dynamic_cast<deriv2*>(*ITE); if (foo != NULL) foo = *ITE; }
Mais bon si j'ai 15 classes dérivées c'est pas top.
Ou bien est-ce que je peux utiliser des constructeurs par copie pour chacune des classes dérivées?
Bref, comment faites vous la copie d'une classe dérivée depuis le tye de base?
Falk Tannhäuser
Michael wrote:
class base //(classe abstraite) { // blabla
public: virtual base* clone() const = 0;
};
class deriv1 : public base { //blabla
public: virtual base* clone() const { return new deriv1(*this); }
};
class deriv2 : public base { //blabla
public: virtual base* clone() const { return new deriv2(*this); }
};
Bien sûr, cela nécessite un constructeur de copie en état de marche dans chaque classe.
Si l'hiérarchie d'héritage est très importante et comporte plusieur s niveaux, il est toutefois possible d'oublier de reimplémenter clone() dans une des classes dérivées, une erreur risque de passer inaperçu e à la compilation. C'est pour ça qu'il est préférable de rendre la fonction clone() non virtuelle dans 'base' et de déléguer à une fon ction privée virtuelle dont on vérifie le résultat :
class base { public: base* clone() const { base* result = do_clone(); assert(typeid(*result) == typeid(*this)); return result; }
private: virtual base* do_clone() const = 0; };
class derivx : public base { // Pas de rédéfinition de clone() private: virtual base* do_clone() const { return new derivx(*this); } };
std::vector<base*> liste; Si je prends un iterator quelconque: std::vector<base*>::const_iterator ITE = ...; je voudrais faire une copie de ce que contient cet iterateur... Seulement comment faire ça? est-ce que je dois tester quelque chose d u type:
deriv1 * toto = dynamic_cast<deriv1*>(*ITE);
base* toto = (**ite).clone(); ou base* toto = (*ite)->clone();
Falk
Michael wrote:
class base //(classe abstraite)
{
// blabla
public:
virtual base* clone() const = 0;
};
class deriv1 : public base
{
//blabla
public:
virtual base* clone() const { return new deriv1(*this); }
};
class deriv2 : public base
{
//blabla
public:
virtual base* clone() const { return new deriv2(*this); }
};
Bien sûr, cela nécessite un constructeur de copie en état de marche
dans chaque classe.
Si l'hiérarchie d'héritage est très importante et comporte plusieur s
niveaux, il est toutefois possible d'oublier de reimplémenter clone()
dans une des classes dérivées, une erreur risque de passer inaperçu e
à la compilation. C'est pour ça qu'il est préférable de rendre la
fonction clone() non virtuelle dans 'base' et de déléguer à une fon ction
privée virtuelle dont on vérifie le résultat :
class base
{
public:
base* clone() const
{
base* result = do_clone();
assert(typeid(*result) == typeid(*this));
return result;
}
private:
virtual base* do_clone() const = 0;
};
class derivx : public base
{
// Pas de rédéfinition de clone()
private:
virtual base* do_clone() const { return new derivx(*this); }
};
std::vector<base*> liste;
Si je prends un iterator quelconque:
std::vector<base*>::const_iterator ITE = ...;
je voudrais faire une copie de ce que contient cet iterateur...
Seulement comment faire ça? est-ce que je dois tester quelque chose d u
type:
deriv1 * toto = dynamic_cast<deriv1*>(*ITE);
base* toto = (**ite).clone();
ou
base* toto = (*ite)->clone();
public: virtual base* clone() const { return new deriv1(*this); }
};
class deriv2 : public base { //blabla
public: virtual base* clone() const { return new deriv2(*this); }
};
Bien sûr, cela nécessite un constructeur de copie en état de marche dans chaque classe.
Si l'hiérarchie d'héritage est très importante et comporte plusieur s niveaux, il est toutefois possible d'oublier de reimplémenter clone() dans une des classes dérivées, une erreur risque de passer inaperçu e à la compilation. C'est pour ça qu'il est préférable de rendre la fonction clone() non virtuelle dans 'base' et de déléguer à une fon ction privée virtuelle dont on vérifie le résultat :
class base { public: base* clone() const { base* result = do_clone(); assert(typeid(*result) == typeid(*this)); return result; }
private: virtual base* do_clone() const = 0; };
class derivx : public base { // Pas de rédéfinition de clone() private: virtual base* do_clone() const { return new derivx(*this); } };
std::vector<base*> liste; Si je prends un iterator quelconque: std::vector<base*>::const_iterator ITE = ...; je voudrais faire une copie de ce que contient cet iterateur... Seulement comment faire ça? est-ce que je dois tester quelque chose d u type:
deriv1 * toto = dynamic_cast<deriv1*>(*ITE);
base* toto = (**ite).clone(); ou base* toto = (*ite)->clone();
Falk
Michael
std::vector<base*> liste; Si je prends un iterator quelconque: std::vector<base*>::const_iterator ITE = ...; je voudrais faire une copie de ce que contient cet iterateur... Seulement comment faire ça? est-ce que je dois tester quelque chose d u
type:
deriv1 * toto = dynamic_cast<deriv1*>(*ITE);
base* toto = (**ite).clone(); ou base* toto = (*ite)->clone();
Merci pour ta réponse...
Donc grâce à cette solution, si *ITE est du type deriv2, on pourra transtyper toto:
base* toto = (*ite)->clone();
en deriv2 sans problème?
std::vector<base*> liste;
Si je prends un iterator quelconque:
std::vector<base*>::const_iterator ITE = ...;
je voudrais faire une copie de ce que contient cet iterateur...
Seulement comment faire ça? est-ce que je dois tester quelque chose d
u
type:
deriv1 * toto = dynamic_cast<deriv1*>(*ITE);
base* toto = (**ite).clone();
ou
base* toto = (*ite)->clone();
Merci pour ta réponse...
Donc grâce à cette solution, si *ITE est du type deriv2, on pourra transtyper
toto:
std::vector<base*> liste; Si je prends un iterator quelconque: std::vector<base*>::const_iterator ITE = ...; je voudrais faire une copie de ce que contient cet iterateur... Seulement comment faire ça? est-ce que je dois tester quelque chose d u
type:
deriv1 * toto = dynamic_cast<deriv1*>(*ITE);
base* toto = (**ite).clone(); ou base* toto = (*ite)->clone();
Merci pour ta réponse...
Donc grâce à cette solution, si *ITE est du type deriv2, on pourra transtyper toto:
C'est bien l'idiome du constructeur virtuel dont il s'agit?
Falk Tannhäuser
Michael wrote:
Je viens de trouver ça: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/abcs-fr.html#[22.5] C'est bien l'idiome du constructeur virtuel dont il s'agit?
Oui, tout à fait.
Falk
Michael wrote:
Je viens de trouver ça:
http://www.ifrance.com/jlecomte/c++/c++-faq-lite/abcs-fr.html#[22.5]
C'est bien l'idiome du constructeur virtuel dont il s'agit?
Je viens de trouver ça: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/abcs-fr.html#[22.5] C'est bien l'idiome du constructeur virtuel dont il s'agit?
Oui, tout à fait.
Falk
Michael
Falk Tannhäuser wrote in news:d2jr2v$1m4$1 @s1.news.oleane.net:
Michael wrote:
Je viens de trouver ça: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/abcs-fr.html#[22.5] C'est bien l'idiome du constructeur virtuel dont il s'agit?
Oui, tout à fait.
Falk
Je te remercie pour ta réponse, je viens de finir d'implémenter tout ça, et ça marche vraiment très bien...
Falk Tannhäuser <falk.tannhauser@crf.canon.fr> wrote in news:d2jr2v$1m4$1
@s1.news.oleane.net:
Michael wrote:
Je viens de trouver ça:
http://www.ifrance.com/jlecomte/c++/c++-faq-lite/abcs-fr.html#[22.5]
C'est bien l'idiome du constructeur virtuel dont il s'agit?
Oui, tout à fait.
Falk
Je te remercie pour ta réponse, je viens de finir d'implémenter tout ça, et
ça marche vraiment très bien...
Falk Tannhäuser wrote in news:d2jr2v$1m4$1 @s1.news.oleane.net:
Michael wrote:
Je viens de trouver ça: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/abcs-fr.html#[22.5] C'est bien l'idiome du constructeur virtuel dont il s'agit?
Oui, tout à fait.
Falk
Je te remercie pour ta réponse, je viens de finir d'implémenter tout ça, et ça marche vraiment très bien...
Michel Michaud
Dans le message d2jjv6$t7d$, [... Code pour fonction clone à rédéfinir dans chaque classe dérivée]
Si l'hiérarchie d'héritage est très importante et comporte plusieurs niveaux, il est toutefois possible d'oublier de reimplémenter clone() dans une des classes dérivées, une erreur risque de passer inaperçue à la compilation. C'est pour ça qu'il est préférable de rendre la fonction clone() non virtuelle dans 'base' et de déléguer à une fonction privée virtuelle dont on vérifie le résultat :
Tant qu'à être rendu là, pourquoi pas un petit coup de CRTP pour ne pas avoir à rédéfinir manuellement et donc éviter toute possibilité d'oublier de le faire :
class Base // La vraie base... { public : virtual Base* Clone() const = 0; // ... autres fonctions };
template <typename T> class BasePourDeriver : public Base { public : Base* Clone() const { return new T(*static_cast<const T*>(this)); } // ... (?) };
class Derive1 : public BasePourDeriver<Derive1> { public : // autres fonctions, mais Clone est hérité... };
class ClDerive2 : public BasePourDeriver<Derive2> { public : // autres fonctions, mais Clone est hérité... };
etc.
On pourrait rendre Base inutilisable pour dérivation directe ailleurs que dans BasePourDeriver, afin d'éviter tout malentendu. À faire en exercice :-)
-- Michel Michaud http://www.gdzid.com FAQ de fr.comp.lang.c++ : http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/
Dans le message d2jjv6$t7d$1@s1.news.oleane.net,
[... Code pour fonction clone à rédéfinir dans chaque classe dérivée]
Si l'hiérarchie d'héritage est très importante et comporte plusieurs
niveaux, il est toutefois possible d'oublier de reimplémenter
clone() dans une des classes dérivées, une erreur risque de passer
inaperçue à la compilation. C'est pour ça qu'il est préférable de
rendre la fonction clone() non virtuelle dans 'base' et de déléguer
à une fonction privée virtuelle dont on vérifie le résultat :
Tant qu'à être rendu là, pourquoi pas un petit coup de CRTP pour ne
pas avoir à rédéfinir manuellement et donc éviter toute possibilité
d'oublier de le faire :
class Base // La vraie base...
{
public :
virtual Base* Clone() const = 0;
// ... autres fonctions
};
template <typename T>
class BasePourDeriver : public Base
{
public :
Base* Clone() const
{
return new T(*static_cast<const T*>(this));
}
// ... (?)
};
class Derive1 : public BasePourDeriver<Derive1>
{
public :
// autres fonctions, mais Clone est hérité...
};
class ClDerive2 : public BasePourDeriver<Derive2>
{
public :
// autres fonctions, mais Clone est hérité...
};
etc.
On pourrait rendre Base inutilisable pour dérivation directe
ailleurs que dans BasePourDeriver, afin d'éviter tout malentendu.
À faire en exercice :-)
--
Michel Michaud mm@gdzid.com
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/
Dans le message d2jjv6$t7d$, [... Code pour fonction clone à rédéfinir dans chaque classe dérivée]
Si l'hiérarchie d'héritage est très importante et comporte plusieurs niveaux, il est toutefois possible d'oublier de reimplémenter clone() dans une des classes dérivées, une erreur risque de passer inaperçue à la compilation. C'est pour ça qu'il est préférable de rendre la fonction clone() non virtuelle dans 'base' et de déléguer à une fonction privée virtuelle dont on vérifie le résultat :
Tant qu'à être rendu là, pourquoi pas un petit coup de CRTP pour ne pas avoir à rédéfinir manuellement et donc éviter toute possibilité d'oublier de le faire :
class Base // La vraie base... { public : virtual Base* Clone() const = 0; // ... autres fonctions };
template <typename T> class BasePourDeriver : public Base { public : Base* Clone() const { return new T(*static_cast<const T*>(this)); } // ... (?) };
class Derive1 : public BasePourDeriver<Derive1> { public : // autres fonctions, mais Clone est hérité... };
class ClDerive2 : public BasePourDeriver<Derive2> { public : // autres fonctions, mais Clone est hérité... };
etc.
On pourrait rendre Base inutilisable pour dérivation directe ailleurs que dans BasePourDeriver, afin d'éviter tout malentendu. À faire en exercice :-)
-- Michel Michaud http://www.gdzid.com FAQ de fr.comp.lang.c++ : http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/
Falk Tannhäuser
Michel Michaud wrote:
Tant qu'à être rendu là, pourquoi pas un petit coup de CRTP pour ne pas avoir à rédéfinir manuellement et donc éviter toute possibi lité d'oublier de le faire :
class Base // La vraie base... { public : virtual Base* Clone() const = 0; // ... autres fonctions };
template <typename T> class BasePourDeriver : public Base { public : Base* Clone() const { return new T(*static_cast<const T*>(this)); } // ... (?) };
class Derive1 : public BasePourDeriver<Derive1> { public : // autres fonctions, mais Clone est hérité... };
Cool! Mais dés qu'il y a un niveau supplémentaire d'héritage, la possibilité d'oubli subsiste :
class PlusDerive1_1 : public Derive1 { // Oups ! Clone() n'est pas rédéfini :-( };
Base* pd11 = new PlusDerive1_1; Base* b = pd11->Clone(); // Grmpfff ! assert(typeid(*b) == typeid(PlusDerive1_1)); // Au revoir...
Falk
Michel Michaud wrote:
Tant qu'à être rendu là, pourquoi pas un petit coup de CRTP pour ne
pas avoir à rédéfinir manuellement et donc éviter toute possibi lité
d'oublier de le faire :
class Base // La vraie base...
{
public :
virtual Base* Clone() const = 0;
// ... autres fonctions
};
template <typename T>
class BasePourDeriver : public Base
{
public :
Base* Clone() const
{
return new T(*static_cast<const T*>(this));
}
// ... (?)
};
class Derive1 : public BasePourDeriver<Derive1>
{
public :
// autres fonctions, mais Clone est hérité...
};
Cool! Mais dés qu'il y a un niveau supplémentaire d'héritage,
la possibilité d'oubli subsiste :
class PlusDerive1_1 : public Derive1
{
// Oups ! Clone() n'est pas rédéfini :-(
};
Base* pd11 = new PlusDerive1_1;
Base* b = pd11->Clone(); // Grmpfff !
assert(typeid(*b) == typeid(PlusDerive1_1)); // Au revoir...
Tant qu'à être rendu là, pourquoi pas un petit coup de CRTP pour ne pas avoir à rédéfinir manuellement et donc éviter toute possibi lité d'oublier de le faire :
class Base // La vraie base... { public : virtual Base* Clone() const = 0; // ... autres fonctions };
template <typename T> class BasePourDeriver : public Base { public : Base* Clone() const { return new T(*static_cast<const T*>(this)); } // ... (?) };
class Derive1 : public BasePourDeriver<Derive1> { public : // autres fonctions, mais Clone est hérité... };
Cool! Mais dés qu'il y a un niveau supplémentaire d'héritage, la possibilité d'oubli subsiste :
class PlusDerive1_1 : public Derive1 { // Oups ! Clone() n'est pas rédéfini :-( };
Base* pd11 = new PlusDerive1_1; Base* b = pd11->Clone(); // Grmpfff ! assert(typeid(*b) == typeid(PlusDerive1_1)); // Au revoir...
Falk
Michel Michaud
Dans le message d307pc$ngi$,
Michel Michaud wrote:
class Base // La vraie base... { public : virtual Base* Clone() const = 0; // ... autres fonctions };
template <typename T> class BasePourDeriver : public Base { public : Base* Clone() const { return new T(*static_cast<const T*>(this)); } // ... (?) };
class Derive1 : public BasePourDeriver<Derive1> { public : // autres fonctions, mais Clone est hérité... };
Cool! Mais dés qu'il y a un niveau supplémentaire d'héritage, la possibilité d'oubli subsiste :
class PlusDerive1_1 : public Derive1 { // Oups ! Clone() n'est pas rédéfini :-( };
Base* pd11 = new PlusDerive1_1; Base* b = pd11->Clone(); // Grmpfff ! assert(typeid(*b) == typeid(PlusDerive1_1)); // Au revoir...
Mais alors il y aura (normalement) une différence importante entre cette classe « intermédiaire » et les autres; en principe, elle serait abstraite aussi par exemple. Lorsque l'on voit cette différence, il faut alors simplement faire une autre classe intermédiaire (Dérivé1PourDériver<T>). Mais je vois surtout qu'il pourrait être intéressant d'intégrer ta solution de vérification dans le code de la classe de base...
-- Michel Michaud http://www.gdzid.com FAQ de fr.comp.lang.c++ : http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/
Dans le message d307pc$ngi$1@s1.news.oleane.net,
Michel Michaud wrote:
class Base // La vraie base...
{
public :
virtual Base* Clone() const = 0;
// ... autres fonctions
};
template <typename T>
class BasePourDeriver : public Base
{
public :
Base* Clone() const
{
return new T(*static_cast<const T*>(this));
}
// ... (?)
};
class Derive1 : public BasePourDeriver<Derive1>
{
public :
// autres fonctions, mais Clone est hérité...
};
Cool! Mais dés qu'il y a un niveau supplémentaire d'héritage,
la possibilité d'oubli subsiste :
class PlusDerive1_1 : public Derive1
{
// Oups ! Clone() n'est pas rédéfini :-(
};
Base* pd11 = new PlusDerive1_1;
Base* b = pd11->Clone(); // Grmpfff !
assert(typeid(*b) == typeid(PlusDerive1_1)); // Au revoir...
Mais alors il y aura (normalement) une différence importante
entre cette classe « intermédiaire » et les autres; en principe,
elle serait abstraite aussi par exemple. Lorsque l'on voit cette
différence, il faut alors simplement faire une autre classe
intermédiaire (Dérivé1PourDériver<T>). Mais je vois surtout qu'il
pourrait être intéressant d'intégrer ta solution de vérification
dans le code de la classe de base...
--
Michel Michaud mm@gdzid.com
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/
class Base // La vraie base... { public : virtual Base* Clone() const = 0; // ... autres fonctions };
template <typename T> class BasePourDeriver : public Base { public : Base* Clone() const { return new T(*static_cast<const T*>(this)); } // ... (?) };
class Derive1 : public BasePourDeriver<Derive1> { public : // autres fonctions, mais Clone est hérité... };
Cool! Mais dés qu'il y a un niveau supplémentaire d'héritage, la possibilité d'oubli subsiste :
class PlusDerive1_1 : public Derive1 { // Oups ! Clone() n'est pas rédéfini :-( };
Base* pd11 = new PlusDerive1_1; Base* b = pd11->Clone(); // Grmpfff ! assert(typeid(*b) == typeid(PlusDerive1_1)); // Au revoir...
Mais alors il y aura (normalement) une différence importante entre cette classe « intermédiaire » et les autres; en principe, elle serait abstraite aussi par exemple. Lorsque l'on voit cette différence, il faut alors simplement faire une autre classe intermédiaire (Dérivé1PourDériver<T>). Mais je vois surtout qu'il pourrait être intéressant d'intégrer ta solution de vérification dans le code de la classe de base...
-- Michel Michaud http://www.gdzid.com FAQ de fr.comp.lang.c++ : http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/