C++ キーワード拡張

提供: RAD Studio
移動先: 案内検索

RAD Studio ライブラリに対する言語サポート (C++) への移動


このセクションでは、VCL をサポートするために C++Builder に実装されているキーワード拡張について説明します。

__classid

__classid 演算子はコンパイラで使用され、指定クラス名の vtable へのポインタを生成します。この演算子は、クラスからメタ クラスを取得するために使用されます。

構文

 __classid (classname)

たとえば、プロパティ エディタ、コンポーネントおよびクラスを登録するとき、TObject の InheritsFrom メソッドとともに __classid が使用されます。次のコードでは、TWinControl から派生する新コンポーネントを作成するための __classid の使用について説明します。

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

__delphirtti

__delphirtti を使用すると、特定の Delphi 互換の型の情報を実行時に取得することができます。__delphirtti 関数の機能は、Delphi で使用可能な TypeInfo 関数と同等です。

例:

 TTypeInfo *ti = __delphirtti(TMyType);

関連項目

__closure

__closure キーワードはメンバ関数へのポインタを特別な型で宣言するために使用されます。標準の C++ では、メンバ関数へのポインタを取得する唯一の方法は、次の例で示すとおり、完全修飾メンバ名を使用することです。

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

ただし、派生クラスのメンバへのポインタを、基底クラスのメンバへのポインタに代入できません。この規則(contravariance:反変性)を次の例で説明します。

 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;

__closure キーワード拡張では、この制限を回避できるだけではありません。closure を使用すると、オブジェクト(たとえば、クラスの特定インスタンス)のメンバ関数へのポインタを取得できます。オブジェクトは、継承の階層に関係ない、任意のオブジェクトが対象です。closure でメンバ関数を呼び出すときにオブジェクトのポインタが自動的に使用されます。次の例では、closure を宣言し、使用する方法について示します。前の例で示した基底クラスと派生クラスは定義されているものと仮定します。

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

コード例の詳細は、TRegExReplace(C++)を参照してください。

closure は次の例で示すとおり、オブジェクトへのポインタでも機能します。

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

派生クラスのインスタンスへのポインタを渡し、これを使用して、基底クラスのメンバ関数へのポインタを取得していますが、標準の C++ では使用できないことに注意してください。

closure は C++Builder RAD 環境の主要な特徴です。これによりオブジェクト インスペクタでイベント ハンドラを割り当てできます。たとえば、TButton オブジェクトには OnClick イベントがあります。TButton クラスの OnClick イベントは、宣言で __closure キーワード拡張を使用するプロパティです。__closure キーワードにより、別のクラスのメンバ関数(一般に TForm オブジェクトのメンバ関数)をプロパティに代入できます。TButton オブジェクトをフォームに配置し、ボタンの OnClick イベントのハンドラを作成すると、C++Builder により、ボタンの親である TForm にあるメンバ関数が作成され、そのメンバ関数が TButton の OnClick イベントに代入されます。このようにして、イベント ハンドラが TButton の特別なインスタンスに関連付けられます。他はありません。

__property

__property キーワードはクラスの属性を宣言します。プログラマにはクラスの他の属性(フィールド)のようにプロパティが見えます。ただし、Object Pascal の該当機能と同様に、C++Builder の __property キーワードには、属性の値を検査し、変更するだけではない、重大な機能がさらに追加されています。プロパティ属性が完全にプロパティへのアクセスを制御するので、クラス自体の中にプロパティを実装する方法に制限がありません。

構文

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

以下に詳しく説明します。

  • type は組み込みまたは前に宣言されたデータ型です。
  • propertyName は任意の有効な識別子です。
  • indexNType は組み込みまたは前に宣言されたデータ型です。
  • indexN はインデックス パラメータ名で、プロパティの読み取り関数と書き込み関数に渡されます。
  • attributes には、read、write、stored、index からコンマ区切りで指定します。

角かっこ内の indexN パラメータは省略可能です。指定する場合は、配列プロパティを宣言します。インデックス パラメータは配列プロパティの読み取りメソッドと書き込みメソッドに渡されます。

次の例では簡単なプロパティの宣言を示します。

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

次の例では複数のプロパティの宣言を示します。プロパティ X はメンバ関数の readX と writeX を使用して読み書きできます。プロパティ Y はメンバ変数 Fy に直接応答し、読み取り専用です。プロパティ Z は計算された読み取り専用値で、クラスのデータ メンバとして、格納されません。最後に、Cells プロパティは、インデックス が 2 の配列プロパティを表します。次の例で示すのは、ユーザーのコードからこれらのプロパティにアクセスする方法です。

 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);

プロパティにはこの例にない他の多くの種類や機能があります。

プロパティではさらに次の処理が可能です。

  • インデックス属性を使用して、複数のプロパティに同じ読み取りメソッドまたは書き込みメソッドを関連付ける。
  • デフォルト値を設定する。
  • フォーム ファイルに格納する。
  • 基底クラスで定義されたプロパティを拡張する。


__published

__publiched キーワードでは、クラスがコンポーネント パレットにある場合に、オブジェクト インスペクタで対象セクションのプロパティが表示されるかどうかを指定します。__published セクションがあるのは、TObject から派生したクラスだけです。

published メンバの可視性規則は public メンバの規則と一致します。published メンバと public メンバの唯一の違いは、__published セクションで宣言されたデータ メンバとプロパティに対して生成される Object Pascal スタイルの実行時型情報(RTTI)だけです。RTTI によりアプリケーションで、RTTI がないと不明なクラス型のデータ メンバ、メンバ関数およびプロパティを動的にクエリできます。

メモ:プロパティ、Pascal 固有または VCL 派生データ メンバ、メンバ関数および closure は __published セクションで使用できます。__published セクションで定義されたフィールドはクラス型であることが必要です。__published セクションで定義されたプロパティで配列プロパティを使用できません。__published セクションで定義されたプロパティ型は、序数型、実数型、文字列型、小集合型、クラス型、またはメソッド ポインタ型のいずれかであることが必要です。

関連項目