2010-11-21 3 views
2

J'ai programmé Java trop longtemps, et j'ai retrouvé du C++. Je veux écrire du code qui donne une classe (soit un type_info, soit son nom dans une chaîne) peut créer une instance de cette classe. Pour simplifier, supposons qu'il suffit d'appeler le constructeur par défaut. Est-ce possible même en C++, et si ce n'est pas le cas dans un futur TR?Possible d'instancier l'objet étant donné son type en C++?

J'ai trouvé un moyen de le faire, mais j'espère qu'il y aura quelque chose de plus "dynamique". Pour les classes que je m'attends à instancier (c'est un problème en soi, comme je veux laisser cette décision à la configuration), j'ai créé une fabrique singleton avec une instance créée statiquement qui s'enregistre avec une autre classe. par exemple. pour la classe Foo, il y a aussi une FooFactory qui a une instance FooFactory statique, de sorte qu'au démarrage du programme le constructeur FooFactory est appelé, qui s'enregistre lui-même dans une autre classe. Ensuite, quand je souhaite créer un Foo à l'exécution, je trouve le FooFactory et l'appelle pour créer l'instance de Foo. Y a-t-il quelque chose de mieux pour faire cela en C++? Je suppose que je viens d'être gâté par une réflexion riche en Java/C#. Pour le contexte, j'essaie d'appliquer certains des concepts de conteneur IOC auxquels je suis tellement habitué dans le monde Java à C++, et j'espère pouvoir le rendre aussi dynamique que possible, sans avoir besoin d'ajouter une usine. classe pour chaque autre classe dans ma demande.

+0

En guise de suivi, est-il possible de passer un "type" en C++? c'est à dire. passer pas un objet Foo, mais la classe Foo, en tant que paramètre à une fonction? L'équivalent Java que je pense est une méthode qui prend un paramètre de classe, et vous pouvez passer dans Foo.class – Greencpp

Répondre

0

Vous pouvez toujours utiliser des modèles, bien que je ne suis pas sûr que ce soit ce que vous cherchez:

template <typename T> 
T 
instantiate() 
{ 
    return T(); 
} 

Ou sur une classe:

template <typename T> 
class MyClass 
{ 
    ... 
}; 
+0

Merci Joe. Oui, l'utilisation de modèles pourrait être un moyen de réduire les lignes de code nécessaires à la mise en œuvre de l'usine, mais j'espère trouver un moyen d'éviter d'écrire une fabrique par classe à créer dynamiquement. Je suppose que je ne le ferai pas. – Greencpp

-1

Non, il n'y a pas moyen de obtenir du nom d'un type au type réel; La réflexion riche est assez cool, mais il y a presque toujours un meilleur moyen.

+1

Oui, je pense qu'essayer d'adapter en gros la façon Java de faire de l'IOC sur C++ est ma première erreur. Pourtant, être capable de câbler dynamiquement des classes dans config a la Spring est très puissant. L'approche de My Factory répond à ce désir, mais pas aussi proprement que je le voudrais. – Greencpp

+1

BTW, qui a donné le -1 ici, et pourquoi ... Je suis intéressé par pourquoi vous n'êtes pas d'accord avec Jonathan. – Greencpp

+0

lol :) Chacun à son propre. –

-1

rien de tel que "var" ou "dynamique" en C++ la dernière fois que j'ai vérifié (même si c'était il ya un moment). Vous pouvez utiliser un pointeur (void *), puis essayer de lancer le casting en conséquence. Aussi, si la mémoire me sert bien, C++ a RTTI qui n'est pas la réflexion mais peut aider à identifier les types à l'exécution.

+1

C++ 0x 'auto' est à peu près ce que C# est' var'. Et les deux n'ont absolument rien à voir avec le typage dynamique. – fredoverflow

0

Bienvenue en C++ :)

Vous avez raison que vous aurez besoin d'un Factory pour créer ces objets, mais vous pourriez ne pas avoir besoin d'un Factory par fichier.

La façon typique d'aller à elle est d'avoir toutes les classes instanciables proviennent d'une classe de base commune, que nous appellerons Base, de sorte que vous aurez besoin d'un seul Factory qui servira un std::unique_ptr<Base> pour vous à chaque fois.

Il y a 2 façons de mettre en œuvre le Factory:

  • Vous pouvez utiliser le modèle Prototype et enregistrer une instance de la classe pour créer, sur lequel une fonction clone sera appelée.
  • Vous pouvez enregistrer un pointeur de fonction ou un foncteur (ou std::function<Base*()> en C++ 0x)

Bien sûr, la difficulté est d'enregistrer les entrées dynamiquement. Ceci est généralement effectué au démarrage lors de l'initialisation statique.

// OO-way 
class Derived: public Base 
{ 
public: 
    virtual Derived* clone() const { return new Derived(*this); } 
private: 
}; 

// start-up... 
namespace { Base* derived = GetFactory().register("Derived", new Derived); } 

// ...or in main 
int main(int argc, char* argv[]) 
{ 
    GetFactory().register("Derived", new Derived(argv[1])); 
} 

// Pointer to function 
class Derived: public Base {}; 

// C++03 
namespace { 
    Base* makeDerived() { return new Derived; } 
    Base* derived = GetFactory().register("Derived", makeDerived); 
} 

// C++0x 
namespace { 
    Base* derived = GetFactory().register("Derived", []() { return new Derived; }); 
} 

L'avantage principal de la classe start-up façon est que vous pouvez parfaitement définir votre Derived dans son propre fichier, l'enregistrement Tuck là, et aucun autre fichier est impacté par vos modifications. C'est génial pour gérer les dépendances. D'un autre côté, si le prototype que vous souhaitez créer nécessite des informations/paramètres externes, vous devez utiliser une méthode d'initialisation, la plus simple étant d'enregistrer votre instance dans main (ou équivalent) une fois que vous avoir les paramètres nécessaires.

Note rapide: le pointeur à la méthode de la fonction est la plus économique (en mémoire) et le plus rapide (en exécution), mais la syntaxe est bizarre ...

En ce qui concerne les questions de suivi.

Oui, il est possible de passer d'un type à une fonction, mais peut-être pas directement:

  • si le type en question est connue au moment de la compilation, vous pouvez utiliser les modèles, mais vous aurez besoin d'une le temps de se familiariser avec la syntaxe
  • sinon, vous aurez besoin de passer une sorte d'identité et d'utiliser l'approche de l'usine

Si vous devez passer quelque chose de semblable à object.class alors il me semble que vous approchez du cas d'utilisation du double dispatch et il serait intéressant de regarder le modèle Visitor.

Questions connexes