11
votes

Enregistrez une classe C ++ afin que, plus tard, une fonction puisse itérez sur toutes les classes enregistrées

J'essaie d'écrire une application chargée de manière dynamique de ses extensions pendant l'exécution. J'ai utilisé Boost Bibliothèque de préprocesseur pour écrire une fonction de préprocesseur qui, compte tenu d'une liste de noms, déclare une classe pour chaque nom (et apportez toutes les sous-classes de certaines classes abstractplugin), puis déclare une séquence MPL boost contenant cette classe. Ensuite, j'ai écrit une classe qui essaie un pointeur à abstractplugin s'il pouvait être coulé à l'un des types de cette séquence mpl. Le problème ici est que ma fonction de préprocesseur nécessite une liste complète de toutes les extensions que je souhaite créer et charger. Y a-t-il une certaine technique qui me permet d'enregistrer chaque extension dans un fichier séparé?

mise à jour:

Je crois, mon explication de la situation était trop vague, j'ai donc décidé de le rendre plus spécifique.

Je voudrais définir une collection de types d'extension. Pour chaque type d'extension, il pourrait y avoir un nombre quelconque d'extensions. Pendant l'exécution, le programme charge la bibliothèque externe, résolvez la fonction de point d'entrée, appelez-la et, par conséquent, obtenez un pointeur. Ensuite, il essaie de lancer ce pointeur à tous les types d'extension enregistrés (en utilisant dynamic_cast , donc les classes des types d'extension Tous hérit de la classe de base polymorphe). Si une mise en forme sur un type d'extension réussit, le pointeur coulée est utilisé dans un appel à un gestionnaire spécial pour ce type d'extension.

Le nombre de types d'extension est connu au moment de la compilation (tandis que, évidemment, le nombre d'extensions est infini). Utilisation de mon APRACH La classe Loader utilise ces connaissances pour vérifier s'il existe un gestionnaire pour chaque type d'extension (le cas échéant, le programme ne compile pas). De plus, mon APREACH ne force pas les classes pour les types d'extension sachez quoi que ce soit sur le chargeur (il est donc facile de modifier le chargeur). Mais ce serait plus pratique si chaque type d'extension s'est enregistré.


1 commentaires

Générez une en-tête une solution acceptable?


3 Réponses :


0
votes

Il n'est pas difficile de mettre en œuvre un tel cadre d'extension à l'aide du modèle d'usine abstrait.

http://en.wikipedia.org/wiki/abstract_factory_pattern

Vous pouvez enregistrer ces fonctions / objets abstraits d'usine dans une liste globale et faire ce que vous voulez faire de la base.


0 commentaires

13
votes

Vous pouvez faire de toutes vos classes auto-inscrites dans une sorte de collection. Voici une approche de squelette:

base.hpp: xxx

base.cpp: < Pré> xxx

maintenant à utiliser ceci dans un client:

dérived.hpp: xxx

dérived.cpp: xxx

le constructeur de la base base :: registraire prend soin de l'enregistrement du Classe dérivé sous le nom "myClass" . Vous pouvez créer des instances de dérivé dynamiquement via: xxx

le code pourrait / doit être amélioré en détectant les enregistrements répétés, imprimer une liste des classes disponibles, etc. Notez que nous évitons de tout problème d'initialisation d'initialisation statique, mon objet de carte de registre réelle un objet statique de bloc, garanti d'être initialisé avant sa première utilisation, et donc détruit uniquement après sa dernière utilisation.


9 commentaires

J'ai considéré quelque chose comme ça, mais je suis plus intéressé par une approche temporelle de compilation. Je ne suis pas sûr qu'il existe un, mais toujours, la terre des modèles C ++ est plein de miracles.


Il n'y a pas de statique. Vous ne pouvez pas créer de classes les enregistrer, car chaque fichier de mise en œuvre a sa propre unité de compilation, et chacun peut être placé dans une bibliothèque différente. La puissance de cette solution est que lorsque vous chargez une bibliothèque dynamique, la classe d'extension est devenue automatiquement disponible automatiquement. C'est un modèle bien connu et très utile.


C'est une très belle mise en œuvre. La seule chose que je ne comprends pas est la = 0 sur la fonction Static Create (). Pour autant que je sache, c'est invalide C ++, car les fonctions statiques ne peuvent jamais être virtuelles. Comment cette partie est-elle censée fonctionner?


@Shenjoku: Cela n'a eu aucun sens du tout! Supprimé. Merci d'avoir tapé. Aucune idée de ce que je pensais. (Également mis à jour pour utiliser des pointeurs uniques.)


Pourquoi cacher la mise en oeuvre de la carte avec l'idiome PIMPL?


@Stackuer: Ce n'est pas ce qui ne se passe pas ici. Il n'y a rien de caché, il n'y a qu'une seule instance de carte globale qui doit être initialisée dans le bon ordre, qui est obtenue en le faisant une variable statique de la fonction locale.


Il y a un problème subtil dans cette réponse. Le registraire défini défini dans dérived.cpp n'est pas garanti d'être construit par le point base :: instantie () est appelé in MAIN. Il n'est garanti que de construire uniquement lorsque l'unité de traduction dérivée.cpp est utilisée par ODR.


Comment la classe dérivée enregistrée si elle n'est pas explicitement incluse quelque part? Je veux dire, ce n'est même pas construit ... Qu'est-ce que je manque?


@Controller: L'enregistrement se produit comme un effet de l'initialisation globale. Cependant, il est indéterminé si cela fonctionnera réellement, car l'initialiseur n'est pas tenu de fonctionner jusqu'à ce que quelque chose de son unité de traduction soit utilisé, ce qui ne se produit pas ici. En pratique, ce code fonctionne parce que les fournisseurs savent que les utilisateurs reposent dessus, mais il n'est pas obligé de travailler par la norme. Les soins doivent être pris lors de la liaison pour s'assurer que la lieur ne jette pas la TU.



-1
votes

Comme il s'avère ce que je veux, c'est impossible. La raison en est "registre" dans ce contexte signifie "mettre une séquence de type à l'intérieur de type" et les séquences de type sont immuables car elles sont des types elles-mêmes. Donc, il faut soit créer cette séquence de type manuellement, soit comme certaines personnes suggéraient de déplacer «l'enregistrement» en runtime.


1 commentaires

Il s'avère que cela peut être fait: Stackoverflow.com/a/21626087/1417883