2010-02-12 1 views
7

Je pense à ajouter des capacités de réflexion à certaines classes C++ (pour ne pas avoir à utiliser RTTI): obtenir des noms de méthodes, des champs déclarés, un nom de classe ... ce genre de choses.Comment implémenteriez-vous la réflexion de base en C++?

Je pensais à analyser les fichiers sources existants, obtenir une liste des champs déclarés & méthodes, et réécrire chaque fichier source, en ajoutant ce genre d'informations à chaque classe.

Que pensez-vous de cette approche? Je voudrais tout faire à partir de zéro, car je pense que c'est une excellente opportunité d'apprendre. Suggéreriez-vous d'autres façons de le faire?

// OFFTOPIC: est-ce ainsi que Qt le fait?

+0

Cela ne coûtera-t-il pas plus cher que RTTI, alors qu'est-ce que cela va faire? – Mark

+0

Dur. Vous ne pouvez pas rassembler le compilateur pour générer les métadonnées dont vous avez besoin à partir du code source. RTTI est nettement insuffisant. Vous devrez écrire votre propre analyseur de langage C++. Cela a été fait ... –

+0

@nobugz: Bien sûr, les gens ont écrit leurs propres analyseurs C++. C'est très loin d'être trivial. C++ est, très simplement, une vraie peine à analyser. –

Répondre

1

Sauf si vous voulez modifier le compilateur C++ ou dépendez extensions des fournisseurs, vous aurez besoin d'un tas de macros RPC qui construisent des structures de données.

3

Vérifiez la bibliothèque Boost.Mirror. Il n'a pas encore été accepté dans Boost, vous devrez donc le download it depuis le Boost Vault.

La bibliothèque est encore en développement et les documents sont rares mais en étudiant le provided examples vous pourriez être en mesure d'atteindre ce que vous voulez.

EDIT: si vous voulez vraiment analyser votre propre code C++, alors vous devriez peut-être envisager clang

+0

Wow. Il semble si concis et facile à utiliser. – Eric

+0

Êtes-vous sarcastique? – Manuel

+2

print_meta_data Eric

3

Je fourche gcc.

2

Oui, voici comment Qt le fait - sauf qu'il n'ajoute pas l'information à la classe elle-même, il crée une nouvelle classe appelée méta-classe qui contient des données statiques sur la classe. C'est mieux pour des raisons évidentes.

Aucune approche pure-C++ n'offrira une réflexion entièrement automatique - le langage ne le permet pas. Il y a beaucoup de tentatives, y compris Boost.Mirror et Boost.Reflection, mais ils exigent tous des ajouts à votre source.

0

Peut-être que vous pouvez utiliser la bibliothèque typeinfo, avec elle vous pouvez maintenant une classe d'objet en cours d'exécution. Exemple:

#include<iostream> 

#include<typeinfo> 
class A{}; 

int main() 
{ 
A a; 

std::cout<<typeid(a).name(); 

} 

Vous pouvez voir plus: http://www.cplusplus.com/reference/std/typeinfo/

[] `s

+0

Je ne veux pas utiliser RTTI. – Geo

1

Vous trouverez peut-être gccxml vaut le détour. Il va (par exemple) convertir this en this, ce qui signifie que vous avez juste à analyser XML au lieu de C++.

Il y a un intéressant SP & E paper qui décrit l'utilisation gccxml en liaison avec un agent de liaison modifié pour « fournir des fonctionnalités Java réflexion comme à des applications C++ de manière propre et non intrusive ».

1

Alter le compilateur pour produire une méthode GetClass statique, renvoyant un pointeur sur un objet de classe décrivant la classe, pour chaque classe définie.

Alter le compilateur/éditeur de liens pour extraire les métadonnées nécessaires et d'autres choses dans les sections spéciales/symboles de l'image exécutable résultant - un peu comme les symboles de débogage sont ajoutés.

GetClass utiliserait (lire/charger/mettre en cache?) Les métadonnées ci-dessus.

Et oui. C'est beaucoup de travail. (Et un bon effet secondaire est que cela vous évite d'éliminer les fichiers d'en-tête car cette information peut maintenant être retirée d'une image)

1

C++ ne supporte pas la réflexion. Les efforts de boost et RTTI sont assez limités et à moitié cuits. Je ne les recommanderais pas.

Vous avez mentionné que vous pouvez commencer à partir de scatch. Eh bien, vous pouvez écrire un lexer C++ en utilisant lex/yacc, ou ANTLR. Beaucoup de travail, mais vous apprendrez beaucoup.

Si écrire un analyseur est une tâche formidable pour vous, il existe d'autres options pour obtenir des métadonnées d'une classe. Microsoft a DIA SDK qui fournit des informations sur les symboles. Doxygen peut générer des fichiers XML que vous pouvez analyser pour obtenir les noms de champs, les noms de méthodes d'une classe. J'ai eu un certain succès en analysant les fichiers XML de doxygen.

Si vous travaillez uniquement avec la plateforme Microsoft, une solution viable consiste à utiliser la bibliothèque de types (TLB). Cela nécessite de convertir la classe en une interface dans MS IDL. MIDL compile l'IDL en .tlb et votre application peut charger le fichier .tlb au moment de l'exécution. Votre application peut obtenir presque toutes les informations sur la classe via l'interface, les propriétés et les méthodes ITypeInfo.

+0

Wow! Doxygen ne m'a même pas traversé l'esprit! Cool un! – Geo

1

Suivez la dixième loi de Greenspun et vous êtes prêt à partir: il suffit d'implémenter une implémentation ad hoc, spécifiée de manière informelle, avec des bugs et lente, de la moitié de Common Lisp. Choisissez une moitié qui prend en charge la mise en œuvre de la réflexion. :)

Ou, voici une idée:

Allumez les fichiers de carte (et éventuellement génération d'assemblage) dans votre construction. Implémentez une application qui génère du code pour créer une bibliothèque dynamique. Vous devriez être en mesure d'obtenir toutes les informations statiques (noms de méthodes, paramètres, types, etc.) sur les classes de la source ou de l'un des artefacts de construction. En utilisant la carte ou l'assemblage, vous devriez pouvoir trouver des adresses de fonction, des décalages de pointeur de fonction virtuelle, des adresses de variables globales, des décalages de variables, des informations sur des variables allouées de pile et de registre, etc. A partir de cette information, construisez une bibliothèque contenant les appels pour obtenir toutes ces informations en passant des noms de type, des pointeurs, des noms de fonctions, etc ...

Maintenant, en C++, écrivez une bibliothèque contenant des fonctions et des macros qui vous permettent de mettre des ID uniques qui vont Compilez le code pour identifier les démarrages de fonctions, tous les appels de réflexion, les décalages EIP sur les appels de réflexion, etc. Utilisez des macros d'assemblage en ligne à des emplacements appropriés qui vous laissent des instructions si nécessaire. ID. En outre, fournissez des fonctions de bibliothèque de pont qui permettront à la fonctionnalité de réflexion de gérer ce qu'elle peut contenir (par exemple, obtenir l'adresse d'une fonction) plutôt que d'appeler la bibliothèque dynamique construite dans l'étape de post-construction.

Enfin, écrivez un éditeur de liens de post-publication. Je suggère "kniltsoPostlink" mais c'est à vous de décider. Dans cette étape, recherchez vos ID uniques (ai-je mentionné pour faciliter la tâche, vous devriez probablement créer les identifiants GUID pour pouvoir les rechercher dans le binaire?) Et, partout où l'ID marque un appel de réflexion vers une fonction, ou un la définition d'une classe, etc., placez suffisamment de données là (dans un format que vous pouvez facilement déterminer juste à temps lorsque vous écrivez la bibliothèque de réflecteurs) puis dans l'ID avant un appel à la bibliothèque de réflecteurs, réécrivez l'appel de sorte que il tire les paramètres dont il a besoin de ces bits de données, ou il suffit de mettre les bits de données là, si applicable, je ne peux pas savoir à l'avance, mais comme vous l'écrivez, ces petits détails apparaîtront à vous.De toute façon, je sais que je n'ai pas donné beaucoup de code, et j'ai l'intention de commencer un projet là-dessus à un moment donné, quand j'aurai assez de temps libre. Je veux dire, chaque petite partie devrait être très simple, alors que vous le faites progressivement, chaque petit morceau devrait devenir clair aussi longtemps que vous suivez les directives énoncées ici. Il est possible qu'une partie soit encore plus simple que ce que j'ai décrit ici, parce que c'était le pire des cas. Vous pouvez même partir sans avoir à réécrire du code pour les appels du réflecteur. le simple fait de placer les données dans les emplacements appropriés peut permettre à la bibliothèque de tirer ces bits comme elle en a besoin sans plus d'informations.

Je suis très content que vous ayez demandé; Je suis très occupé en ce moment, mais si vous obtenez une nuit gratuite, j'imagine que ce sera un bon début pour une première version, et je serai heureux de vous présenter dès que possible.

;)

+0

Wow, je vois que ça fait un an et demi que vous avez posé cette question, je suis désolé que vous ayez dû vous passer d'une vraie réponse pendant si longtemps, mais c'est bon de savoir que je pourrais vous aider. : D ♡ – shelleybutterfly

+0

Très intéressant, et très détaillé. Je vais faire quelques lectures dessus. Je vous remercie! – Geo

+0

Eh bien, je vous en prie. :) Sachez que même si je pense réellement que cela peut fonctionner, ce n'est qu'une feuille de route. (Les commentaires à propos de la facilité avec laquelle tout cela serait en d'autres termes serait tout ironique.) Mais je crois que, pour répondre à la question de façon itérative de trouver la meilleure solution, cela peut être fait. (Je ne suis pas sûr que ce soit plus facile que d'écrire une extension en C++ et d'étendre gcc pour le compiler.) ... Est-ce que les sons sont amusants comme je l'ai décrit, un peu comme: oubliez C++, vous êtes Je réfléchis si ça vous plait ou non ... :) – shelleybutterfly