Anzeigen: Delphi C++
Anzeigeeinstellungen

Schlüsselwort-Erweiterungen in C++

Aus RAD Studio XE2
Wechseln zu: Navigation, Suche

Nach oben zu Sprachunterstützung für die VCL (C++)

Dieser Abschnitt beschreibt die in C++Builder zur Unterstützung der VCL implementierten Schlüsselwort-Erweiterungen.

Inhaltsverzeichnis

__classid

Mit dem Operator __classid erzeugt der Compiler einen Zeiger auf die V-Tabelle des angegebenen Klassennamens. Mit diesem Operator wird die Metaklasse für eine Klasse ermittelt.

Syntax

 __classid (classname)

__classid wird beispielsweise verwendet, wenn Eigenschaftseditoren, Komponenten und Klassen sowie über die Methode InheritsFrom von TObject registriert werden. Der folgende Quelltext zeigt die Verwendung von __classid zum Erstellen einer neuen, von TWinControl abgeleiteten Komponente:

 namespace Ywndctrl
 {
   void __fastcall PACKAGE Register() {
     TComponentClass classes[1] = {__classid(MyWndCtrl)};
     RegisterComponents("Additional", classes, 0);
   }
 }

__delphirtti

Mit __delphirtti können zur Laufzeit Informationen für einen spezifischen Delphi-kompatiblen Typ ermittelt werden. Die __delphirtti-Funktion entspricht der Delphi-Funktion TypeInfo.

Beispiel:

 TTypeInfo *ti = __delphirtti(TMyType);

Siehe auch

__closure

Mit dem Schlüsselwort __closure wird ein spezieller Typ eines Zeigers auf eine Member-Funktion deklariert. In Standard-C++ kann ein Zeiger auf eine Member-Funktion nur mit dem voll qualifizierten Member-Namen erstellt werden, wie im folgenden Beispiel gezeigt:

 class base {
 public:
     void func(int x) {
     };
 };
 
 typedef void(base::*pBaseMember)(int);
 
 int main(int argc, char * argv[])
 {
     base baseObject;
     pBaseMember m = &base::func; // Get pointer to member ‘func’.
 
     // Call ‘func’ through the pointer to member.
     (baseObject.*m)(17);
     return 0;
 }

Sie können jedoch keinen Zeiger auf einen Member einer abgeleiteten Klasse einem Zeiger auf einen Member einer Basisklasse zuweisen. Diese Regel (als Kovarianz bezeichnet) wird im folgenden Beispiel illustriert:

 class derived : public base {
 public:
     void new_func(int i) {
     };
 };
 
 int main(int argc, char * argv[])
 {
     derived derivedObject;
     pBaseMember m = &derived::new_func; // ILLEGAL
 
     return 0;

Mit der Schlüsselwort-Erweiterung __closure können Sie diese Beschränkung umgehen. Mit einem Closure lässt sich ein Zeiger auf eine Member-Funktion für ein Objekt (d.h. eine bestimmte Instanz einer Klasse) erstellen. Das Objekt kann jedes beliebige Objekt - unabhängig von seiner Vererbungshierarchie - sein. Der Zeiger des Objekts wird automatisch beim Aufruf der Member-Funktion über das Closure verwendet. Das folgende Beispiel zeigt, wie ein Closure deklariert und eingesetzt wird. Dabei wird davon ausgegangen, dass die Basis- und abgeleiteten Klassen bereits definiert sind.

 int main(int argc, char * argv[]) {
     derived derivedObject;
     void(__closure * derivedClosure)(int);
 
     // Get a pointer to the ‘new_func’ member.
     // Note the closure is associated with the
     // particular object, ‘derivedObject’.
     derivedClosure = derivedObject.new_func;
 
     derivedClosure(3); // Call ‘new_func’ through the closure.
     return 0;
 }

Ein Codebeispiel finden Sie unter TRegExReplace (C++).

Closures arbeiten auch mit Zeigern auf Objekte, wie im folgenden Beispiel:

 void func1(base * pObj)
 {
     // A closure taking an int argument and returning void.
     void(__closure * myClosure)(int);
 
     // Initialize the closure .
     myClosure = pObj->func;
 
     // Use the closure to call the member function.
     myClosure(1);
     return;
 }
 
 int main(int argc, char * argv[])
 {
     derived derivedObject;
     void(__closure * derivedClosure)(int);
 
     derivedClosure = derivedObject.new_func; // Same as before...
     derivedClosure(3);
 
     // We can use pointers to initialize a closure, too.
     // We can also get a pointer to the ‘func’ member function
     // in the base class.
     func1(&derivedObject);
     return 0;
 }

Beachten Sie bitte, dass ein Zeiger an die Instanz der abgeleiteten Klasse übergeben wurde, und dass damit ein Zeiger auf die Member-Funktion in der Basisklasse erstellt wurde - das wäre in Standard-C++ nicht zulässig.

Closures sind ein Schlüsselkonzept in der RAD-Umgebung von C++Builder. Sie ermöglichen das Zuweisen einer Ereignisbehandlungsroutine im Objektinspektor. Angenommen, ein TButton-Objekt hat das Ereignis OnClick. In der Klasse TButton ist das Ereignis OnClick eine Eigenschaft, die die Schlüsselwort-Erweiterung __closure in ihrer Deklaration verwendet. Das Schlüsselwort __closure ermöglicht das Zuweisen einer Member-Funktion einer anderen Klasse (normalerweise einer Member-Funktion in einem TForm-Objekt) zu der Eigenschaft. Wenn Sie ein TButton-Objekt auf einem Formular platzieren und dann eine Behandlungsroutine für das Ereignis OnClick für TButton erstellen, legt C++Builder eine Member-Funktion in dem TButton übergeordneten TForm an und weist diese Member-Funktion dem OnClick-Ereignis von TButton zu. Auf diese Weise wird die Ereignisbehandlungsroutine dieser Instanz von TButton und keiner anderen zugeordnet.

__property

Das Schlüsselwort __property deklariert ein Attribut einer Klasse. Eine Eigenschaft erscheint für Programmierer wie ein weiteres Attribut (Feld) einer Klasse. Wie die Entsprechung in Object Pascal fügt aber das Schlüsselwort __property von C++Builder einen deutlich erweiterten Funktionsumfang hinzu, der über das Untersuchen und Ändern des Attributwerts hinausgeht. Weil Eigenschaftsattribute den Zugriff auf die Eigenschaft vollständig steuern, gibt es keine Beschränkungen hinsichtlich der Implementierung der Eigenschaft innerhalb der Klasse.

Syntax

__property type propertyName [index1Type index1 ][indexNType indexN ] = { attributes  }; 


  • type ist ein intrinsischer oder bereits deklarierter Datentyp.
  • propertyName ist ein beliebiger gültiger Bezeichner.
  • indexNType ist ein intrinsischer oder bereits deklarierter Datentyp.
  • indexN ist der Name eines Indexparameters, der an die Lese- und Schreibfunktionen der Eigenschaft übergeben wird.
  • attributes ist eine durch Komma getrennte Folge von read, write, stored oder index.

Die indexN-Parameter in eckigen Klammern sind optional. Wenn vorhanden, deklarieren sie eine Array-Eigenschaft. Die index-Parameter werden an die Lese- und Schreibmethoden der Array-Eigenschaft übergeben.

Das folgende Beispiel zeigt einige einfache Eigenschaftsdeklarationen:

 class  PropertyExample { 
 
  private: 
 
  int  Fx,Fy; 
 
  float  Fcells[100][100]; 
 
  protected : 
  int  readX() {  return (Fx);  } 
  void  writeX( int  newFx) { Fx = newFx;  } 
 
  double  computeZ() { 
 
  // Do some computation and return a floating-point value... 
 
  return (0.0); 
 
  }  float  cellValue( int  row,  int  col) {  return (Fcells[row][col]); } 
 
  public: __property int  X = { read=readX, write=writeX };  __property int  Y = { read=Fy };  __property double  Z = { read=computeZ };  __property float  Cells[int row][int col] = { read=cellValue }; 
 
  };

Dieses Beispiel zeigt mehrere Eigenschaftsdeklarationen. Die Eigenschaft X verfügt durch die Member-Funktionen readX bzw. writeX über Lese-Schreib-Zugriff. Die Eigenschaft Y ist direkt der Member-Variable Fy zugeordnet und ist schreibgeschützt. Die Eigenschaft Z ist ein schreibgeschützter Wert, der berechnet wird; sie wird nicht als Daten-Member in der Klasse gespeichert. Die Eigenschaft Cells demonstriert eine Array-Eigenschaft mit zwei Indizes. Das nächste Beispiel zeigt, wie auf diese Eigenschaften im Quelltext zugegriffen wird:

 PropertyExample myPropertyExample ; 
  myPropertyExample.X = 42; // Evaluates to: myPropertyExample.WriteX(42) ; 
  int  myVal1 = myPropertyExample.Y; // Evaluates to: myVal1 = myPropertyExample.Fy ; 
  double  myVal2 = myPropertyExample.Z; // Evaluates to: myVal2 = myPropertyExample.ComputeZ() ; 
  float  cellVal = myPropertyExample[3][7]; // Evaluates to : 
 
  // cellVal = myPropertyExample.cellValue(3,7);

Eigenschaften haben viele andere Variationen und Features, die in diesem Beispiel nicht gezeigt wurden.

Eigenschaften können auch:

  • Dieselbe Lese- oder Schreibmethode mit dem Attribut index mehr als einer Eigenschaft zuweisen.
  • Standardwerte haben.
  • In einer Formulardatei gespeichert werden.
  • Eine in einer Basisklasse definierte Eigenschaft erweitern.


__published

Das Schlüsselwort __published legt fest, dass Eigenschaften in diesem Abschnitt im Objektinspektor angezeigt werden, wenn sich die Klasse in der Komponentenpalette befindet. Nur von TObject abgeleitete Klassen können __published-Abschnitte haben.

Die Regeln für die Sichtbarkeit von published-Membern sind identisch mit denen der public-Member. Der einzige Unterschied zwischen published- und public-Membern besteht darin, dass für in einem __published-Abschnitt deklarierte Daten-Member und Eigenschaften Laufzeittypinformationen (RTTI) im Object Pascal-Stil erzeugt werden. RTTI ermöglichen einer Anwendung, Daten-Member, Member-Funktionen und Eigenschaften eines ansonsten unbekannten Klassentyps dynamisch abzufragen.

Hinweis: Eigenschaften, Pascal-intrinsische oder aus der VCL abgeleitete Daten-Member, Member-Funktionen und Closures sind in __published-Abschnitten zulässig. In einem __published-Abschnitt definierte Felder müssen einen Klassentyp haben. In einem __published-Abschnitt definierte Felder dürfen keine Array-Eigenschaften sein. Eine in einem __published-Abschnitt definierte Eigenschaft muss ein Ordinal-, Real-, String-, Small Set-, Class- oder Methodenzeigertyp sein.

Siehe auch

Frühere Versionen
In anderen Sprachen