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

Déclarer un objet detype incconu à l'avance

6 réponses
Avatar
nico
Bonjour,

Je dois réaliser une sorte de mini-interpréteur (dans le cadre d'un projet
plus gros), j'ai refléchi sérieusement à la manière de l'implémenter et ai
commencé à coder. J'ai défini toute mes classes/interfaces mais voila que
je bloque lors du codage de la fonction centrale... J'y avais songé avant
pourtant et j'avais pensé que ce serait plus simple.

Donc voici mon problème dans une situation simplifiée :

J'ai une classe de base Object dont hérite plusieurs classes : String,
Int, ... et j'ai une std::string qui contient le nom d'une de ces classes.

Je voudrais allouer une instance d'une classe (héritant de Object) dont le
nom est contenu dans ma chaine :

std::string str = "Int";
Object * obj = fonction_magique(str);

avec :

Object * fonction_magique(std::string str)
{
return dynamic_cast<Object*>(new_magique(str));
}

Evidemment je ne peux pas utiliser les templates vu que ca doit etre
dynamique, je ne peux pas non plus faire un switch géant avec des valeurs
rtti (ou autre) puisque il y a un nombre de classe potentiellement
illimité :)

J'ai pensé aussi (même si c'est stupide) à faire un new Object() puis faire
un casting vers Int() ou String() mais c'est pareil je ne connais pas le
type à l'avance pour mon casting.

Ensuite comment appeler les fonctions membres ? La je pensais résoudre le
problème avec un map contenant nom_de_la_fonction <->
pointeur_vers_la_fonction qui serait initialisé dans mes classes héritants
de Object. Ce tableau pourrait être initialisé dans le constructeur, et je
pourrais avoir une fonction virtuelle de Object comme ca : void *
getFunctionPtr(std::string functionName)...

En fait c'est surtout l'allocation qui va pas. Je cherche le moyen de
pouvoir trimballer un type comme le fait l'opérateur sizeof ou les macros
va_* mais je ne sais pas si c'est réaliste.

Donc si vous avez une idée ou un lien ca serait sympa :)

En tout cas merci d'avance.

--
nico

6 réponses

Avatar
Fabien LE LEZ
On Sat, 13 Aug 2005 15:58:39 +0200, nico :

Object * fonction_magique(std::string str)
{
return dynamic_cast<Object*>(new_magique(str));


Un petit problème ici : si j'ai bien compris, "new_magique()" renvoie
un pointeur vers un objet d'une classe dérivée de Object.

Il y a donc conversion
(pointeur vers un objet "dérivé") -> (ptr vers un objet "de base")
Cette conversion est automatique :
return new_magique(str);

dynamic_cast<> est utile dans l'autre sens :

Base* ptrB= new Derivee;
Derivee* ptrD= dynamic_cast<Derivee*> (ptrB);

Evidemment je ne peux pas utiliser les templates vu que ca doit etre
dynamique, je ne peux pas non plus faire un switch géant avec des valeurs
rtti (ou autre) puisque il y a un nombre de classe potentiellement
illimité :)


[Note en passant : boost::any peut peut-être t'aider ?]

De toutes façons, il faut que chaque classe soit "enregistrée" dans
une liste quelconque.

class String: public Object
{
...
};

MACRO_ENREGISTRE_CLASSE (String)






typedef Object* (*CreateurDObject)();

static std::map <std::string, Object>* ptr_map_createurs= 0;

class EnregistreClasse
{
public:
EnregistreClasse (CreateurDObject fonction_creation,
std::string const &nom);
/* Ce pseudo-constructeur a pour mission de créer
"ptr_map_createurs" si ce n'est déjà fait, puis
(*ptr_map_createurs)[nom]= fonction_creation;
*/
};

#define MACRO_ENREGISTRE_CLASSE( nom_classe)
Object* Createur##nom_classe()
{
return new nom_classe;
}

static EnregistreClasse enregistreur_##nom_classe
(Createur##nom_classe, nom_classe)




Object * fonction_magique(std::string str)
{
std::map<...>::const_iterator it_fonction_creation ptr_map_createurs-> find (str);
if (it_fonction_creation != ptr_map_createurs->end())
{
return (*it_fonction_creation)();
}
}

Avatar
Fabien LE LEZ

De toutes façons, il faut que chaque classe soit "enregistrée" dans
une liste quelconque.


Note : tout ce qui suit cette phrase est très probablement des
élucubrations d'un esprit fatigué, postées dans le seul but de faire
hurler ceux qui savent faire ça proprement (et/ou ont lu "Design
Patterns").

Enfin bref, à prendre avec des pincettes.

Avatar
Fabien LE LEZ
On Sat, 13 Aug 2005 16:29:36 +0200, Fabien LE LEZ
:

static std::map <std::string,
Object


"CreateurDObject", ici, bien sûr.

* ptr_map_createurs= 0;



Bien évidemment, il ne faut jamais écrire ça, mais plutôt :

typedef std::string NomClasse;
typedef std::map <NomClasse, Object> ListeCreateurs;
static ListeCreateurs* ptr_map_createurs= 0;


Avatar
nico
Salut,


De toutes façons, il faut que chaque classe soit "enregistrée" dans
une liste quelconque.


J'avais bien pensé à enregistrer les classes dans une liste mais je ne
voyais pas comment ! Là l'idée de stocker des pointeurs de fonction n'est
vraiment pas mal ! Donc je prend, merci beaucoup !


--
nico

Avatar
Fabien LE LEZ
On Sat, 13 Aug 2005 16:29:36 +0200, Fabien LE LEZ
:

(Createur##nom_classe, nom_classe)


Tiens, encore une erreur... Il faut écrire :

(Createur##nom_classe, #nom_classe)

Avatar
Arnaud Meurgues
nico wrote:

J'avais bien pensé à enregistrer les classes dans une liste mais je ne
voyais pas comment ! Là l'idée de stocker des pointeurs de fonction n'est
vraiment pas mal ! Donc je prend, merci beaucoup !


Autre possibilité : si Object a une fonction virtuelle clone(), on peut
enregistrer des instances directement et utiliser clone() pour produire
une nouvelle instance.

--
Arnaud