Instanciation de sous-classe

Signaler
Messages postés
6535
Date d'inscription
lundi 16 décembre 2002
Statut
Modérateur
Dernière intervention
22 août 2010
-
Messages postés
371
Date d'inscription
dimanche 4 janvier 2004
Statut
Membre
Dernière intervention
23 septembre 2009
-
Bonjour

J'ai la hiérarchie de classes suivante: A0, A1, A2, A3, A4... sont des sous-classes de A.
J'ai besoin d'instancier une de ces sous-classes selon la valeur d'une variable n. Pour le moment j'ai un code qui ressemble à ca:

A* p;
switch(n)
{
case 0:
p = new A1();
break;
case 1:
p = new A1();
break;
...
}

J'aimerais une solution plus jolie que ca, d'autant qu'il y a en réalité environ 15 sous classes.
J'ai pensé à un tableau de A* contenant un spécimen de chaque sous-classe, et utiliser une méthode virtual A* A::make(...)=0 pour créer un objet (les constructeurs actuels des sous-classes prennent les mêmes paramètres).
Cette solution vous semble-t-elle plus efficace, ou en avez vous une autre?

23 réponses

Messages postés
6535
Date d'inscription
lundi 16 décembre 2002
Statut
Modérateur
Dernière intervention
22 août 2010
7
Pardon le code de départ est de la forme
A* p;
switch(n)
{
case 0:
p = new A0();
break;
case 1:
p = new A1();
break;
...
}
Messages postés
700
Date d'inscription
mardi 30 décembre 2003
Statut
Membre
Dernière intervention
27 janvier 2009
4
salut;

t'auras du mal a faire plus joli, avec ton tableau, t'es aussi obligé
de construire un spécimen de tes 15 sous classes, donc en plus
t'auras deux créations a la place d'une. Ca ne ferait que déplacer le
code que tu trouves pas beau ailleurs ...

le n est il vraiment determiné a l'execution ?

sinon utilise des templates.



a+
Messages postés
6535
Date d'inscription
lundi 16 décembre 2002
Statut
Modérateur
Dernière intervention
22 août 2010
7
n est déterminé à l'éxxécution, et sa valeur change pendant l'exécution. Le truc c'est que le code que j'ai mis est exécuté souvent, ce qui fait que la création des 15 spécimen ne me pose pas problème, et ce code la ne sera exécuté qu'une seule fois. Après j'utilise tranquillement mon tableau.
Comment faire avec des templates?
Messages postés
700
Date d'inscription
mardi 30 décembre 2003
Statut
Membre
Dernière intervention
27 janvier 2009
4
si tu connais n qu'a l'execution, tu dois te servir de fonctions virtuelles.

je disais ca parce que parfois la virtualité est utilisée excessivement
alors que le type est connu a la compilation; mais que cela permet
d'etre plus 'general'



par ex:



class A {

virtual void func();

}



class B : public A

{

func() { autre chose }

}



peut parfois etre remplacé par qqc du genre:



class B {};



class A{

template <class T>

T* func() { return 0 };



// specialistation pour B

template <>

B* func() { return (B*)1; }

};



enfin bref
Messages postés
6535
Date d'inscription
lundi 16 décembre 2002
Statut
Modérateur
Dernière intervention
22 août 2010
7
euh ca répond pas trop à mon problème ca...
Messages postés
700
Date d'inscription
mardi 30 décembre 2003
Statut
Membre
Dernière intervention
27 janvier 2009
4
ué je t'ai dit que ca ne peut y répondre que si tu connais n a la compilation:

" le n est il vraiment determiné a l'execution ?

sinon utilise des templates."
Messages postés
6535
Date d'inscription
lundi 16 décembre 2002
Statut
Modérateur
Dernière intervention
22 août 2010
7
ok. Mais tu me dis d'utilsier les fonctions virtuelles. Oui mais comment? Comme je fais, avec un tableau?
Messages postés
700
Date d'inscription
mardi 30 décembre 2003
Statut
Membre
Dernière intervention
27 janvier 2009
4
pourquoi pas?
Messages postés
6535
Date d'inscription
lundi 16 décembre 2002
Statut
Modérateur
Dernière intervention
22 août 2010
7
je sais pas justement, je demande ce que vous pensez de mon idée
Messages postés
700
Date d'inscription
mardi 30 décembre 2003
Statut
Membre
Dernière intervention
27 janvier 2009
4
ben de toutes facons une classes mere avec 15 filles, ca va pas faire un truc joli
Messages postés
475
Date d'inscription
dimanche 3 octobre 2004
Statut
Membre
Dernière intervention
11 août 2006
3
L'idée ca serait de pouvoir faire

A * p = A::construct(n);



Pour ca il faut que A ai un tableau static de fonction construisant un A, je ne vois que ca ?



#include

#include <typeinfo>



struct A

{

virtual ~A() {}



static A * construct(std::size_t n)

{

return (construct_functions[n])();

}



protected:



typedef A * (* construct_function_type) ();



static construct_function_type construct_functions[];



struct init_type {

init_type(int id, construct_function_type f) {

construct_functions[id] = f;

}

};

};

// dans le .cpp

A::construct_function_type A::construct_functions[15];



struct A0 : A

{



private:



static const std::size_t id = 0;



static A * construct()

{

return new A0();

}



static init_type init;

};

// dans le .cpp

A0::init_type A0::init(id, construct);





struct A1 : A

{



private:



static const std::size_t id = 1;



static A * construct()

{

return new A1();

}



static init_type init;

};

// dans le .cpp

A1::init_type A1::init(id, construct);



int main()

{

int n = 1;

A * p = A::construct(n);

std::cout << typeid(*p).name() << '\n';

}





Le tableau est "statique" mais on vector si tu tiens à ce que ce soit plus modulable.
Messages postés
6535
Date d'inscription
lundi 16 décembre 2002
Statut
Modérateur
Dernière intervention
22 août 2010
7
J'ai mis un temps à comprendre la! Ca n'a rien a voir, mais pourquoi tu mets struct, et pas class?
La struct init_type a juste pour objet de mettre la fonction dans le tableau c'est ca? (j'ai pas l'habitude de créer des types ad hoc comme ca)
C'est une solution que tu viens d'inventer, ou bien tu l'a déja utilisée?
Messages postés
475
Date d'inscription
dimanche 3 octobre 2004
Statut
Membre
Dernière intervention
11 août 2006
3
Oui je viens d'inventer, donc c'est certainement pas optimale. Ne
cherche pas à comprendre quelque chose dans mon utilisation de
struct/class, au debut j'avais mis class, puis struct... enfin ca
revient au meme.



L'astuce avec la struct init c'est de faire ce genre de pres-traitement, ici l'initialisation du tableau.



Et si jamais tu te demandes pourquoi

A1::init_type A1::init(id, construct);

fonctionne alors qu'on aurait du logiquement ecrire

A1::init_type A1::init(A1::id, A1::construct);

c'est à cause du "koening-lookup" sur la portée des noms (koening c'est un mec connue du commité c++).
Messages postés
6535
Date d'inscription
lundi 16 décembre 2002
Statut
Modérateur
Dernière intervention
22 août 2010
7
Ouais koening c'est le pseudo que j'utilise quand j'ai envie de raconter des bobards...
Messages postés
475
Date d'inscription
dimanche 3 octobre 2004
Statut
Membre
Dernière intervention
11 août 2006
3
Et pourquoi koening ?
Messages postés
6535
Date d'inscription
lundi 16 décembre 2002
Statut
Modérateur
Dernière intervention
22 août 2010
7
nan laisse tomber, c'était une boutade, je pensais que c'était un mec vraiment connu
Messages postés
475
Date d'inscription
dimanche 3 octobre 2004
Statut
Membre
Dernière intervention
11 août 2006
3
Ouai, enfin de toute façon j'ai écorché le nom, voila le lien

http://cpptips.hyperformix.com/cpptips/koenig_search2



Dans l'exemple j'ai oublié delete p;
Messages postés
371
Date d'inscription
dimanche 4 janvier 2004
Statut
Membre
Dernière intervention
23 septembre 2009

vecchio > As tu le TC++PL ed.3 ? Une solution C++ est avancée par BS. Ca répond peut etre à ton besoin d'une manière peut plus séduisante encore.

Ca se base sur une map qui fait la correspondance entre n et la fonction de création de l'instance An.

struct An // n = {0,1,2,3....15}
{
static A* clone() { return new An; }
}

typdef A* (PF*)();
map

map[0] = &A0::clone;
map[1] = &A1::clone;
...

Je te laisse deviner la suite.

Cordialement,
Xterminhate.
Messages postés
371
Date d'inscription
dimanche 4 janvier 2004
Statut
Membre
Dernière intervention
23 septembre 2009

Dans ton cas, remplaced la map par le vector (je suis allé un peu vite). Dans l'exemple de BS, la décision était basé sur un string et non sur un entier.....
Messages postés
6535
Date d'inscription
lundi 16 décembre 2002
Statut
Modérateur
Dernière intervention
22 août 2010
7
Oui, ta fonction clone corrsepond à la construct de steve