オブジェクトの識別性とインスタンス化
C++ モデルと Object Pascal モデル への移動
C++ では、クラスのインスタンスは実際のオブジェクトです。そのオブジェクトを直接操作することもできますし、参照かポインタを通じてそのオブジェクトに間接的にアクセスすることもできます。
CPP_class by_value;// an object of type CPP_clas s
CPP_class& ref = by_value;// a reference to the object by_value, abov e
CPP_class* ptr = new CPP_class();// a pointer to an object of type CPP_clas s
これに対して、Object Pascal では、型オブジェクトの変数は常にそのオブジェクトを間接的に参照します。すべてのオブジェクトのメモリは動的に割り当てられます。たとえば、Object Pascal クラス OP_class がある場合は、
ref: OP_class ;
ref := OP_class.Create ;
OP_class* ref = new OP_class;
C++ と Object Pascal における参照の違い
ドキュメントでは、Object Pascal クラス インスタンスの変数は参照であるとよく言われますが、その動作についてはポインタのように記述されています。これは、インスタンスの変数がどちらの特性も備えているからです。Object Pascal のオブジェクト参照は C++ ポインタに似ていますが、以下の点が異なります。
- Object Pascal の参照は暗黙的に逆参照されます(この場合、動作はむしろ C++ の参照に似ています)。
- Object Pascal の参照には、ポインタ算術演算は定義されていません。
Object Pascal の参照と C++ の参照を比較すると、類似点と同時に相違点もあります。どちらの言語の参照も暗黙的に逆参照されます。ただし、
- Object Pascal の参照は再バインドできるのに対して、C++ の参照はできません。
- Object Pascal の参照は nil でもかまわないのに対して、C++ の参照は有効なオブジェクトを参照していなければなりません。
FireMonkey フレームワークと RTL フレームワークの根底にある設計上の決定事項には、インスタンスを格納するこの種の変数を使用することを前提としているものがあります。Object Pascal の参照に最も近い C++ 言語構文要素はポインタです。そのため、C++Builder では、ほぼすべての FireMonkey と RTL のオブジェクト識別子が C++ ポインタに変換されます。
メモ: Object Pascal の var パラメータは C++ の参照に近いです。
オブジェクトのコピー
C++ とは異なり、Object Pascal のコンパイラでは、オブジェクトのコピー操作を組み込みサポートしていません。このセクションでは、この違いが Delphi 形式クラスの代入演算子やコピー コンストラクタに及ぼす影響について説明します。Delphi 形式のクラスは System::TObject から直接または間接に派生します。
代入演算子
Object Pascal の代入演算子(:=)はクラスの代入演算子(operator=())ではありません。Object Pascal の代入演算子では、オブジェクトではなく参照をコピーします。次のコードでは、B と C はどちらも同じオブジェクトを参照しています。
B, C: TButton ;
B:= TButton.Create(ownerCtrl) ;
C:= B ;
この例は、C++Builder では次のようなコードに変換されます。
TButton *B = NULL ;
TButton *C = NULL ;
B = new TButton(ownerCtrl) ;
C = B;// makes a copy of the pointer, not the object
C++Builder における Delphi 形式のクラスは、代入演算子については、Object Pascal の言語規則に従います。つまり、次のコードでは、逆参照ポインタ間の代入は、ポインタではなくオブジェクトをコピーしようとしているため、無効です。
TRTLStyleClass *p = new TRTLStyleClass ;
TRTLStyleClass *q = new TRTLStyleClass ;
*p = *q;// not allowed for Delphi style class objects
メモ: Delphi 形式のクラスについては、C++ 構文を使用して参照をバインドすることは依然として有効です。たとえば、以下のコードは有効です。
TRTLStyleClass *ptr = new TRTLStyleClass ;
TRTLStyleClass &ref = *ptr;// OK for Delphi style classes
これは代入演算子の使用と同じではありませんが、構文が非常に似ているので、説明と比較のためにここで触れておきます。
コピー コンストラクタ
Object Pascal には、コピー コンストラクタが組み込まれていません。そのため、C++Builder における Delphi 形式のクラスには、コピー コンストラクタが組み込まれていません。次のサンプル コードでは、コピー コンストラクタを使って TButton ポインタを作成しようとしています。
TButton *B = new TButton(ownerCtrl) ;
TButton *C = new TButton(*B);// not allowed for Delphi style class object s
Delphi 形式クラスの組み込みコピー コンストラクタを前提としたコードを書かないでください。C++Builder で Delphi 形式クラスのオブジェクトのコピーを作成するには、オブジェクトをコピーするメンバ関数のコードを記述します。あるいは、RTL TPersistent クラスの下位クラスで、オブジェクト間でデータをコピーするように Assign メソッドをオーバーライドすることができます。これは、たとえば、リソース画像が格納される TBitmap や TIcon などの FMX グラフィックス クラスでよく行われます。最終的に、オブジェクトのコピー方法はプログラマ(コンポーネント作成者)が決定できますが、標準の C++ で使用されるコピー メソッドの中には Delphi 形式のクラスに使用できないものがあることに注意してください。
関数引数としてのオブジェクト
上記のとおり、C++ と Object Pascal では、インスタンスを格納する変数はまったく同じではありません。関数の引数としてオブジェクトを渡す場合には、この点に注意する必要があります。C++ では、値、参照、ポインタのいずれでもオブジェクトを関数に渡すことができます。Object Pascal では、オブジェクトを値で関数に渡す場合は、そのオブジェクト引数は既にオブジェクトへの参照になっていることを覚えておいてください。したがって、値渡しされるのは実のところ参照であって、実際のオブジェクトではありません。C++ の場合のような実際のオブジェクトの値渡しに相当するものは、Object Pascal にはありません。関数に渡される Delphi 形式のオブジェクトは Object Pascal の規則に従います。