Delphi-RTTI und C++Builder

Aus RAD Studio
Wechseln zu: Navigation, Suche

Nach oben zu Mit RTTI arbeiten


Typermittlung zur Laufzeit (Überlegungen)

Begriffserklärung

Die Delphi-RTTI unterscheidet sich von der Standard-C++-RTTI:

  • Mit der Delphi-RTTI lassen sich Felder, Methoden usw. einer Klasse untersuchen.
  • Mit der C++-RTTI können Sie den Typ einer Variable ermitteln und Typen hinsichtlich Gleichheit oder Sortierreihenfolge vergleichen.

Hinweis: Die Compiler-Option Projekt > Optionen > C++-Compiler > RTTI aktivieren bezieht sich auf die Standard-C++-RTTI.

RTTI-Erzeugung

Nur Klassen im Delphi-Stil können in C++-RTTI-Informationen im Delphi-Stil haben (siehe __declspec(delphiclass)).

RTTI-Informationen können für alle Arten von Klassen-Membern (Methoden, Felder, Eigenschaften) mit jeder Sichtbarkeit (__published, public, protected, private) erzeugt werden. Zur Steuerung der RTTI-Erzeugung können die folgenden Spezifikationen verwendet werden:

Ein Beispiel:

#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;
}

Konsolenausgabe:

wrHead: int @ 00

In diesem Beispiel wird die Klasse RTTI mit der Funktion __delphirtti (die einen Zeiger auf eine TTypeInfo-Variable zurückgibt) extrahiert. Dasselbe können Sie mit dem Operator __classid ausführen. Siehe den folgenden Code:

	TRttiInstanceType *cls = dynamic_cast<TRttiInstanceType*>
		(context.GetType(__classid(TBuffer)));

Hinweis: Mit __delphirtti extrahierte RTTI-Informationen können je nach Plattform unterschiedlich sein. Beispielsweise gibt __delphirtti eines char16_t unter iOS und macOS eine PTypeInfo zurück, die den Delphi-RTTI-Informationen für Delphi-WideChar entspricht.

Auf der Windows-Plattform gibt __delphirtti eines wchar_t eine PTypeInfo zurück, die den Delphi-RTTI-Informationen für Delphi-WideChar entspricht.

Diese Funktionalität wird in dem folgenden Codebeispiel gezeigt:

#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;
}

Ausgabe:

Plattform Ausgabe

WIN64

Kind=1, Name='char16_t'

Kind=9, Name='Char'

iOS

Kind=9, Name='Char'

Kind=9, Name='wchar_t'

Typ-Rooting

Delphi-RTTI-Informationen für in der Sprache C++ definierte Klassen können nicht mit den Methoden FindType und GetTypes ermittelt werden. Das liegt daran, dass FindType und GetTypes Laufzeit-Packages durchsuchen, aber der C++-Linker kein Typ-Rooting ausführt.

Andererseits weist der Delphi-Linker die RTTI-Informationen in Package-Informationstabellen aus. Das bedeutet, dass Sie in C++ die RTTI nach in Delphi-Modulen (Packages) gefundenen Units, wie im folgenden Code, durchsuchen können:

TRttiContext context;
TRttiType *rttiType = context.FindType("Classes.TStringList");
printf("%ls", rttiType->ToString()); // displays TStringList

Hinweis: Auf der iOS-Plattform wird ein statisches Linken durchgeführt und deshalb erfolgt für RTTI kein Rooting. Sie können aber die RTTI ermitteln, wenn Sie die Methode GetType verwenden, wie in dem folgenden Codebeispiel gezeigt:

  TRttiContext context;
  TRttiType *rttiType = context.GetType(__delphirtti(Fmx::Layouts::TLayout));

  if (rttiType == NULL) {
     ShowMessage("RTTI not generated");
  }  else {
    ShowMessage(rttiType->ToString());
  }

Attribute

Delphi-Attribute werden in C++Builder nicht unterstützt. C++Builder unterstützt C++11-Attribute, die sich von Delphi-Attributen unterscheiden:

  • Delphi-Attribute stellen zusätzliche Informationen für den Programmierer dar und können zur Laufzeit extrahiert werden.
  • C++11-Attribute stellen zusätzliche Informationen für den Compiler dar und sind nicht spezifisch für RTTI.

Siehe auch

Delphi RTTI

Delphi-RTTI in C++Builder

C++-RTTI