Object Pascal では、すべてのオブジェクトはスタック上ではなくメモリのヒープ領域に作成されるため、C++ のようにコンパイラによってコンストラクターが自動的に呼び出されることはありません。オブジェクトの構築と破棄はプログラマの責任です。
オブジェクトを構築するには、まずオブジェクトにメモリを割り当てる必要があります。このステップは、Object Pascal のコンパイラ (いわゆる「コンパイラ マジック」) によってサポートされています。 Magic)" の場合、プログラマはこのプロセスに参加する必要はありません。その後、オブジェクトのデータ メンバーを初期化する必要があり、コンパイラがそれらを「クリア」する責任を負いますが、特別な割り当てがある場合は、それを完了できます。コンストラクター内; オブジェクトが破棄されるとき 要求されたリソース (オブジェクト自体が占有しているメモリーではない) を解放する必要があります。これらのタスクは、オブジェクト自体が占有しているメモリーのリサイクルもデストラクターの責任です。 「コンパイラマジック」。
オブジェクトメモリの割り当てとリサイクル
コンパイラがオブジェクトにメモリを割り当てるとき、コンパイラが提供するサポートは、コンストラクターを呼び出す前に次のアセンブリ コード行を挿入することです。
テストDL、DL
jz +$08
ESPを追加、-$10
call @ClassCreate // このコード行に注目してください
上記のコードの最後の行は、system.pas ファイルの 8949 行目で _ClassCreate 関数を呼び出します (Delphi 6 の対象)。この関数は、各オブジェクトに適切なメモリを具体的に割り当てます。メモリ割り当てが完了すると、クラスのコンストラクターが呼び出され、データ メンバーが初期化されます。その後、コンパイラは次のアセンブリ コード行を挿入します。
テストDL、DL
jz +$0f
@AfterConstruction を呼び出します
dWord ptr fs をポップ:[$00000000]
ESP を追加、$0c
主な仕事は、各オブジェクト インスタンスの AfterConstruction を呼び出すことです。この呼び出しは、C++Builder 用に予約されています。
同様に、オブジェクトを破棄するときは、最初にクラスのデストラクターを呼び出して、オブジェクトによって要求されたリソースを解放する必要があります。その後、オブジェクト自体が占有するメモリ空間がリサイクルされ、コンパイラがデストラクターを呼び出した後に次のアセンブリ コードを挿入することでこの作業が完了します。
@BeforeDestruction を呼び出す
テストDL、DL
ジェイル +$05
@ClassDestroy に電話してください
これらのコードによって行われる作業は、オブジェクトの構築およびメモリの割り当て時に行われる処理に対応しており、主に system.pas の 8997 行目で _ClassDestroy 関数を呼び出します。
コンストラクターとデストラクター
コンストラクターを定義するには、Constructor キーワードを使用します。慣例により、コンストラクターの名前は Create です (もちろん他の名前も使用できますが、これは決して良い設計ではありません)。のように:
タイプ
TMyFamily = class // ファミリ用に定義されたクラス
プライベート
FMyFatherName : String; あなたの父親の名前
FMyMotherName : String; あなたの母親の名前
… // あなたの家族の他のメンバー
公共
コンストラクター Create(strFatherName, strMotherName : String);
…… // 他のメソッド
終わり;
クラスにコンストラクターを提供しない場合、そのオブジェクトは作成できるのかと疑問に思うかもしれません。答えは「はい」です。理由は前述しましたが、オブジェクト自体が占有するメモリの割り当てはコンパイラによって完了されます。また、Object Pascal では、すべてのクラス (TObject クラス自体を除く) が TObject クラスから派生するため、コンパイラーは TObject.Create() コンストラクターを呼び出しますが、この関数は空の関数であり、TMyFamily クラスには影響しません。データ メンバー (FMyFatherName、FMyMotherName) が初期化されると、TObject.Create() は父親または母親をまったく認識しないため、それらは自動的に空の文字列 (つまり '') にクリアされます。
オブジェクトを作成するとき、コンストラクターは次の形式で直接呼び出されます。
MyFamilyObject := TMyFamily.Create('Zhang', 'Li');
デストラクターを定義するには、Destructor キーワードを使用します。慣例により、デストラクターには Destroy という名前が付けられます。のように:
タイプ
TMyClass = クラス
公共
デストラクター Destroy();
終わり;
デストラクター宣言の最後に override ステートメントを追加する理由は、ポリモーフィズムの場合にオブジェクトを正しく破棄できるようにするためです (ポリモーフィズムについてはセクション 2.4 で詳しく説明します)。 override キーワードを追加しない場合、コンパイラは「メソッド 'Destroy' は基本型 'TObject' の仮想メソッドを隠します」のような警告を出します。この警告は、定義した Destroy が基本クラスの仮想メソッド TObject.Destroy() を非表示にすることを意味します。この場合、ポリモーフィックな状況ではオブジェクトを正しく破棄できません。
注: デストラクターは、override ステートメントを使用して宣言する必要があります。
同様に、クラス内に解放する必要がある特別なリソースがない場合は、デストラクターを定義する必要はありません。ただし、オブジェクトを破棄するときは、Destroy() を直接呼び出すのではなく、オブジェクトの Free() メソッドを呼び出す必要があります。
MyFamilyObject.Free();
これは、Free() メソッドがオブジェクト自体が nil かどうかを判断し、nil でない場合は安全性を高めるためにオブジェクトの Destroy() が呼び出されるからです。これを行うためのより安全な方法がある今、それを行わない理由は確かにありません。
注: オブジェクトに対して Destroy() を直接呼び出さないでください。代わりに Free() を呼び出してください。
このことから、Object Pascal では、オブジェクトによって適用されたリソースの割り当てと解放にのみ注意を払う必要があり、オブジェクト自体が占有するスペースを気にする必要はないことが結論付けられます。