Delphi RTTI et C++Builder
Remonter à Utilisation des informations RTTI
Sommaire
Découverte du type à l'exécution (réflexion)
Désambiguïsation
Les informations RTTI de Delphi sont différentes des informations RTTI standard de C++ :
- Les informations RTTI de Delphi vous permettent d'explorer les champs, les méthodes d'une classe, et ainsi de suite.
- Les informations RTTI de C++ vous permettent d'identifier le type d'une variable et de comparer l'égalité des types, ou l'ordre de tri.
Remarque : L'option Projet > Options > Compilateur C++ > Activer RTTI du compilateur se réfère aux informations RTTI standard de C++.
Génération des informations RTTI
Seules les classes de style Delphi peuvent avoir des informations de style Delphi dans C++ (voir __declspec(delphiclass)).
Des informations RTTI peuvent être générées pour tout type de membre de classe (méthodes, champs, propriétés) avec toute visibilité (__published, public, protected, private). Pour contrôler la génération des informations RTTI, les spécifications suivantes peuvent être utilisées :
- #pragma explicit_rtti (c'est l'équivalent C++ de {$RTTI})
- __declspec(delphirtti) (c'est l'équivalent C++ de {$M}/{$TYPEINFO})
- __published
Exemple :
#include <System.hpp>
#include <Rtti.hpp>
#include <tchar.h>
#include <stdio.h>
// Enable RTTI generation for private fields
#pragma explicit_rtti fields(private)
class __declspec(delphiclass) TBuffer {
private:
int wrHead, rdHead;
// ...
public:
TBuffer() {
}
};
// ---------------------------------------------------------------------------
int _tmain(int argc, _TCHAR* argv[]) {
TRttiContext context;
// Get class RTTI
TRttiInstanceType *cls = dynamic_cast<TRttiInstanceType*>
(context.GetType(__delphirtti(TBuffer)));
if (cls) {
// Get field RTTI
TRttiField *field = cls->GetField("wrHead");
if (field) {
printf("%ls", field->ToString().c_str());
}
else {
puts("\"wrHead\" doesn't have RTTI");
}
}
else {
puts("\"TBuffer\" doesn't have RTTI");
}
return 0;
}
Sortie console :
wrHead: int @ 00
Dans cet exemple, les informations RTTI de classe sont extraites à l'aide de la fonction __delphirtti (qui renvoie un pointeur sur une variable TTypeInfo). Il est possible de faire la même chose avec l'opérateur __classid. Voir le code suivant
TRttiInstanceType *cls = dynamic_cast<TRttiInstanceType*>
(context.GetType(__classid(TBuffer)));
Remarque : Les informations RTTI extraites avec __delphirtti peuvent différer selon les plates-formes. Par exemple, sur iOS et macOS, la fonction __delphirtti d'un caractère char16_t renvoie une variable PTypeInfo qui correspond aux informations RTTI de Delphi pour le type WideChar de Delphi.
Sur la plate-forme Windows, la fonction __delphirtti d'un caractère wchar_t renvoie une variable PTypeInfo qui correspond aux informations RTTI de Delphi pour le type WideChar de Delphi.
Cette fonctionnalité est illustrée dans l'exemple de code suivant :
#include <stdio.h>
static System::UTF8String getTypeInfoName(System::Typinfo::PTypeInfo ti)
{
#ifndef _DELPHI_NEXTGEN
return System::UTF8String(ti->Name);
#else
int len = ti->Name;
const char* p = reinterpret_cast<char*>(&(ti->Name));
return System::UTF8String(p+1, len);
#endif
}
int main()
{
System::Typinfo::PTypeInfo pti;
pti = __delphirtti(char16_t);
printf("Kind=%d, Name='%s'\n", pti->Kind, getTypeInfoName(pti).c_str());
pti = __delphirtti(wchar_t);
printf("Kind=%d, Name='%s'\n", pti->Kind, getTypeInfoName(pti).c_str());
return 0;
}
Sortie :
Plate-forme | Sortie |
---|---|
WIN64 |
Kind=1, Name='char16_t' Kind=9, Name='Char' |
iOS |
Kind=9, Name='Char' Kind=9, Name='wchar_t' |
Enracinement du type
Vous ne pouvez pas utiliser les méthodes FindType et GetTypes pour obtenir les informations RTTI de Delphi pour des classes définies en langage C++. La raison est que FindType et GetTypes effectuent des recherches dans les packages d'exécution, et que le lieur C++ n'effectue aucun enracinement de type.
D'autre part, le lieur Delphi enracine les informations RTTI dans les tables d'information de packages. Cela signifie, qu'en C++, vous pouvez parcourir les informations RTTI pour les unités trouvées dans les modules Delphi (packages), comme dans le code suivant
TRttiContext context;
TRttiType *rttiType = context.FindType("Classes.TStringList");
printf("%ls", rttiType->ToString()); // displays TStringList
Remarque : Sur la plate-forme iOS, la liaison est effectuée de façon statique, donc aucune information RTTI n'est enracinée. Cependant, vous pouvez obtenir les informations RTTI si vous utilisez la méthode GetType, comme illustré dans l'exemple de code suivant :
TRttiContext context;
TRttiType *rttiType = context.GetType(__delphirtti(Fmx::Layouts::TLayout));
if (rttiType == NULL) {
ShowMessage("RTTI not generated");
} else {
ShowMessage(rttiType->ToString());
}
Attributs
Les attributs Delphi ne sont pas pris en charge dans C++Builder. C++Builder prend en charge les attributs C++11, qui sont différents des attributs Delphi :
- Les attributs Delphi représentent des informations supplémentaires pour le programmeur et ils peuvent être extraits à l'exécution.
- Les attributs C++11 représentent des informations supplémentaires pour le compilateur et ne sont pas spécifiques à RTTI.