C++Builder ライブラリでのオブジェクト生成
C++ モデルと Object Pascal モデル への移動
オブジェクトの生成は C++Builder と Delphi で異なります。このセクションでは、このトピックを概観し、これら 2 つのアプローチを C++Builder ではどう組み合わせているかを説明します。
C++ でのオブジェクト生成
標準の C++ では、仮想基底クラス、基底クラス、派生クラスの順にコンストラクタが呼び出されます。C++ 構文では、コンストラクタの初期化リストを使用して、基底クラスのコンストラクタを呼び出します。オブジェクトの実行時型は、現在呼び出されているコンストラクタのクラスの実行時型です。仮想メソッド ディスパッチは、オブジェクトの実行時型に従って行われ、オブジェクトの生成時にそれに合わせて変わります。
Delphi でのオブジェクト生成
Delphi では、必ず呼び出されるのはインスタンス化されるクラスのコンストラクタだけですが、基底クラスのメモリは割り当てられます。直接の基底クラスのコンストラクタ呼び出しは、それぞれ対応する派生クラスのコンストラクタで inherited を呼び出すことで行われます。慣例的に、VCL、RTL、FireMonkey ライブラリでのクラスでは inherited を使用して、(空でない)基底クラス コンストラクタを呼び出します。ただし、これは言語上の要件ではないことに注意してください。オブジェクトの実行時型はインスタンス化されるクラスの実行時型として直ちに確定し、基底クラス コンストラクタの呼び出しに合わせて変わることはありません。仮想メソッド ディスパッチは、オブジェクトの実行時型に従って行われるため、オブジェクトの生成時に変わることはありません。
C++Builder でのオブジェクト生成
Delphi 形式のオブジェクトは任意の Object Pascal オブジェクトと同じように生成されますが、その際に C++ 構文を使用します。つまり、基底クラス コンストラクタの呼び出しの方法と順序は C++ 構文に従い、すべての非 VCL、非 RTL、非 FireMonkey 基底クラスと最も近い上位 VCL-RTL-FireMonkey クラスについては初期化リストを使用します。この VCL-RTL-FireMonkey 基底クラスが、最初にコンストラクタを呼び出されるクラスです。必要に応じて、Object Pascal の方法に従い、inherited を使って、そのクラス自身の基底クラス コンストラクタが呼び出されます。したがって、VCL-RTL-FireMonkey 基底クラスは C++ の場合とは逆の順序でコンストラクタが呼び出されます。その後、最も遠い上位クラスから派生クラスへと、C++ 基底クラスがすべて順にコンストラクタを呼び出されます。オブジェクトの実行時型と仮想メソッド ディスパッチは Object Pascal に準拠します。
以下の図では、MyBase(TWinControl の直接の下位クラス)から派生する Delphi 形式のクラス MyDerived のインスタンス生成について説明しています。MyDerived と MyBase は C++ で実装されています。TWinControl は、Object Pascal で実装されている VCL クラスです。
継承関係とコンストラクタの呼び出し順序
メモ: 本来の VCL-RTL-FireMonkey クラスについて最も下位の上位クラスから TObject へとコンストラクタが順に呼び出された後、MyBase のコンストラクタが呼び出され、最後に派生クラスのコンストラクタが呼び出されるため、C++ プログラマにはコンストラクタの呼び出し順序が逆に見えるかもしれません。
メモ: TPersistent にコンストラクタがないため、TComponent は inherited を呼び出しません。TObject のコンストラクタは空なので、呼び出されません。仮にこれらのクラス コンストラクタも呼び出されたとすると、呼び出し順序は図のようになります(図ではこれらのクラスが灰色で表示されています)。
C++、Object Pascal、C++Builder でのオブジェクト生成モデルを以下の表にまとめておきます。
オブジェクト モデルの比較
C++ | Object Pascal | C++Builder |
---|---|---|
コンストラクタの呼び出し順序 | ||
仮想基底クラス、基底クラス、派生クラスの順。 |
インスタンス化されるクラスのコンストラクタだけが自動的に呼び出されます。後続のクラスのコンストラクタが呼び出される場合は、最も下位のものからルートへと順に呼び出されます。 |
最も近い VCL-RTL-FireMonkey 基底クラスのコンストラクタが呼び出された後は、Object Pascal モデルに従ってコンストラクタが呼び出され、最後に C++ モデルに従ってコンストラクタが呼び出されます(ただし、仮想基底クラスは使用できません)。 |
基底クラス コンストラクタの呼び出し方法 | ||
コンストラクタの初期化リストから自動的に呼び出します。 |
必要に応じて、派生クラス コンストラクタの本体で inherited キーワードを使って、随時明示的に呼び出します。 |
コンストラクタの初期化リストから、VCL-RTL-FireMonkey 基底クラスとなる最も近い上位クラスのコンストラクタまで、自動的に呼び出します。その後は、Object Pascal の方法に従い、inherited を使ってコンストラクタを呼び出します。 |
オブジェクトの生成中の実行時型 | ||
現在のコンストラクタ クラスの型に応じて変わります。 |
インスタンス化されるクラスの実行時型として直ちに確定します。 |
インスタンス化されるクラスの実行時型として直ちに確定します。 |
仮想メソッド ディスパッチ | ||
基底クラス コンストラクタが呼び出されるにつれて、オブジェクトの実行時型に従って変わります。 |
オブジェクトの実行時型に従います。すべてのクラス コンストラクタ呼び出しの間中、変わりません。 |
オブジェクトの実行時型に従います。すべてのクラス コンストラクタ呼び出しの間中、変わりません。 |
「基底クラス コンストラクタの仮想メソッドの呼び出し」では、これらの相違点の意味について説明します。