6. Dephi のオブジェクト指向拡張
1995 年に発売された Delphi の言語は Object Pascal と呼ばれました。
Delphi のオブジェクト指向拡張を細かいトコまで説明していると大変なのでざっくりとした説明に留めます。
なお、サンプルコード中で //
による行コメントを多用していますが、ご了承ください 1。
See also:
6.1. Delphi のオブジェクト型
Delphi には Turbo Pascal 由来のオブジェクト型が下位互換性 2 のために残されています。非推奨でドキュメントも非常に少ないのですが、今でも使う事ができます。
program ObjTest;
{$APPTYPE CONSOLE}
type
TObj = object
private
FValue: Integer;
public
constructor Init;
destructor Done; virtual;
function Multiply(n: Integer): Integer;
property Value: Integer read FValue write FValue;
end;
PObj = ^TObj;
{ TObj }
constructor TObj.Init;
begin
FValue := 1;
end; { TObj.Init }
destructor TObj.Done;
begin
;
end; { TObj.Done }
function TObj.Multiply(n: Integer): Integer;
begin
result := FValue * n
end; { TObj.Multiply }
var
sObj: TObj;
dObj: PObj;
begin
// Static
sObj.Init;
sObj.Value := 3;
Writeln(sObj.Multiply(5));
// Dynamic
dObj := New(PObj, Init);
try
dObj^.Value := 7;
Writeln(dObj^.Multiply(9));
finally
Dispose(dObj, Done);
end;
Readln;
end. { Main }
Delphi では、ポインタの逆参照を自動的に想定する参照モデルを使うため、動的なオブジェクトを指すための逆参照演算子 (^
) を省略する事ができます。上記コードだと、メインブロック中の ^
を取り除いても動作します 3。定義部の ^TObj
の前にある ^
は逆参照演算子ではないので省略できません。
See also:
6.2. Delphi のクラス型
クラス
という用語は Delphi 1 において、次のように定義されています。
データと関連コードを表す機能を一つの単位に集めたリスト。クラスには定義にある機能だけではなく、上位オブジェクトから継承した機能も含まれます。「クラス」という用語は「オブジェクト型」と同義です。
Turbo Pascal では クラス
という用語を使っていなかったので混乱しそうになりますが、Delphi ではオブジェクト型もクラス型も (広義の) クラス型です。クラス型はレコード型と同様、構造化型の一種です。
クラス型は型宣言部 (type) にて "型名 = class (親クラス) ~ end;" として定義します。親クラスは省略できますが、省略した場合にはルートクラスである TObject を継承します。
クラスには次に挙げるようなメンバーがあります。
フィールド
フィールドはオブジェクトに属する変数のようなものです。他言語での "メンバ変数" や "インスタンス変数" に相当します。通常は可視性を private で定義します。
なお、クラスのフィールドを "クラスフィールド" とか "クラス変数" と呼んではいけません。そちらには別の意味があります。
メソッド
メソッドとはクラス型宣言内で宣言された、オブジェクトに対して操作を行う手続き (procedure) または関数 (function) を指します。他言語の "メンバ関数" に相当します。
コンストラクタとデストラクタはオブジェクトの作成と廃棄を制御する特殊なメソッドです。
なお、クラスのメソッドを "クラスメソッド" とか "クラス関数" と呼んではいけません。そちらには別の意味があります。
プロパティ
プロパティはオブジェクトの属性を定義するものです。フィールドの値を読み書きするメソッド (ゲッター/セッター) をカプセル化したりできます。プロパティの例には、フォームのキャプション、フォントのサイズ、データベーステーブルの名前などがあります。
See also:
6.2.1. クラス型の定義
次のようにしてクラスを定義できます。
type
TCls = class(TObject) { TObject を継承したクラス型 TCls の定義 }
private
FValue: Integer;
end;
- ルートクラスは TObject です。
- 親クラスを指定しなかった場合の親クラスは TObject です。
- 多重継承はできません。
- 可視性指定子があります。
- プロパティがあります。
- クラスメソッドがあります。
- 静的なオブジェクトは作れません。
6.2.2. クラス型の定義
クラスの作成と破棄は次のようにして行います。次のコードは ObjTest.dpr
のクラス型版です。
program ClsTest;
{$APPTYPE CONSOLE}
type
TCls = class
private
FValue: Integer;
public
constructor Create;
destructor Destroy; override;
function Multiply(n: Integer): Integer;
property Value: Integer read FValue write FValue;
end;
{ TCls }
constructor TCls.Create;
begin
FValue := 1;
end; { TCls.Create }
destructor TCls.Destroy;
begin
inherited;
end; { TCls.Destroy }
function TCls.Multiply(n: Integer): Integer;
begin
result := FValue * n
end; { TCls.Multiply }
var
Cls: TCls;
begin
Cls := TCls.Create;
try
Cls.Value := 7;
Writeln(Cls.Multiply(9));
finally
Cls.Free;
end;
Readln;
end. { Main }
コンストラクタ Create() と Free() メソッドですね。自動参照カウント (ARC) 4 が有効な場合には DisposeOf() メソッドを使って破棄します。
コンストラクタには結果型の定義はありませんが、コンストラクタが生成したオブジェクトまたはコンストラクタを呼び出したオブジェクトへの参照が返されます。with 文を使って、変数の宣言なしにクラスを使う事もできます。
with TStringList.Create do
begin
Add('Hello,');
Add('world.');
Writeln(Text);
Free;
end;
クラスではクラス型とポインタ型を別々に宣言したり、オブジェクトポインタを明示的に逆参照する必要はありません。
See also:
- System.TObject.Free (DocWiki)
- System.TObject.DisposeOf (DocWiki: 10.3 Rio)
- Delphi モバイル コンパイラでの自動参照カウント (DocWiki: 10.3 Rio)
6.2.3. 可視性指定子 (Visibility Specifiers)
Delphi の可視性指定子とその範囲は次の通りです。
同一ユニット | 別ユニット | 下位クラス | 実行時 型情報 |
オートメーション 型情報 |
|
---|---|---|---|---|---|
strict private 5 | × | × | × | × | × |
private | 〇 | × | × | × | × |
strict protected 5 | × | × | 〇 | × | × |
protected | 〇 | × | 〇 | × | × |
public | 〇 | 〇 | 〇 | × | × |
published | 〇 | 〇 | 〇 | 〇 | × |
automated (Win32) | 〇 | 〇 | 〇 | × | 〇 |
published を使うには {$M+}
コンパイラ指令を付ける必要があります。また、published に指定できるフィールドはクラス型またはインターフェイス型に限定されます。
unit Unit1;
interface
type
TValue = class
private
FValue: Integer;
public
property Value: Integer read FValue write FValue;
end;
TClsA = class
procedure Dummy; virtual;
strict private
FStrictPrivate: TValue;
private
FPrivate: TValue;
strict protected
FStrictProtected: TValue;
protected
FProtected: TValue;
public
FPublic: TValue;
published
FPublished: TValue;
end;
TClsB = class(TClsA)
procedure Dummy; override;
end;
procedure DummyU1;
implementation
procedure DummyU1;
var
V: Integer;
ClsA: TClsA;
ClsB: TClsB;
begin
// --------------------------------------
// Unit1.TClsA
// Unit1.ClsA <- アクセス
// --------------------------------------
ClsA := TClsA.Create;
try
try
// V := ClsA.FStrictPrivate.Value; // NG
V := ClsA.FPrivate.Value;
// V := ClsA.FStrictProtected.Value; // NG
V := ClsA.FProtected.Value;
V := ClsA.FPublic.Value;
V := ClsA.FPublished.Value;
except
end;
finally
ClsA.Free;
end;
// --------------------------------------
// Unit1.TClsA, Unit1.TClsB(継承)
// Unit1.ClsB <- アクセス
// --------------------------------------
ClsB := TClsB.Create;
try
try
// V := ClsB.FStrictPrivate.Value; // NG
V := ClsB.FPrivate.Value;
// V := ClsB.FStrictProtected.Value; // NG
V := ClsB.FProtected.Value;
V := ClsB.FPublic.Value;
V := ClsB.FPublished.Value;
except
end;
finally
ClsB.Free;
end;
end; { Dummy }
{ TClsA }
procedure TClsA.Dummy;
var
V: Integer;
begin
// --------------------------------------
// Unit1.TClsA
// Unit1.TClsA.Self <- アクセス
// --------------------------------------
V := Self.FStrictPrivate.Value;
V := Self.FPrivate.Value;
V := Self.FStrictProtected.Value;
V := Self.FProtected.Value;
V := Self.FPublic.Value;
V := Self.FPublished.Value;
end;
{ TClsB }
procedure TClsB.Dummy;
var
V: Integer;
begin
// --------------------------------------
// Unit1.TClsA, Unit1.TClsB(継承)
// Unit1.TClsB.Self <- アクセス
// --------------------------------------
//V := Self.FStrictPrivate.Value;
V := Self.FPrivate.Value;
V := Self.FStrictProtected.Value;
V := Self.FProtected.Value;
V := Self.FPublic.Value;
V := Self.FPublished.Value;
end;
end.
unit Unit2;
interface
uses
Unit1;
type
TClsC = class(TClsA)
procedure Dummy; override;
end;
procedure DummyU2;
implementation
procedure DummyU2;
var
V: Integer;
ClsA: TClsA;
ClsB: TClsB;
ClsC: TClsC;
begin
// --------------------------------------
// Unit1.TClsA
// Unit2.ClsA <- アクセス
// --------------------------------------
ClsA := TClsA.Create;
try
try
// V := ClsA.FStrictPrivate.Value; // NG
// V := ClsA.FPrivate.Value; // NG
// V := ClsA.FStrictProtected.Value; // NG
// V := ClsA.FProtected.Value; // NG
V := ClsA.FPublic.Value;
V := ClsA.FPublished.Value;
except
end;
finally
ClsA.Free;
end;
// --------------------------------------
// Unit1.TClsA, Unit1.TClsB
// Unit2.ClsB <- アクセス
// --------------------------------------
ClsB := TClsB.Create;
try
try
// V := ClsB.FStrictPrivate.Value; // NG
// V := ClsB.FPrivate.Value; // NG
// V := ClsB.FStrictProtected.Value; // NG
// V := ClsB.FProtected.Value; // NG
V := ClsB.FPublic.Value;
V := ClsB.FPublished.Value;
except
end;
finally
ClsB.Free;
end;
// --------------------------------------
// Unit1.TClsA, Unit2.TClsC
// Unit2.ClsC <- アクセス
// --------------------------------------
ClsC := TClsC.Create;
try
try
// V := ClsC.FStrictPrivate.Value; // NG
// V := ClsC.FPrivate.Value; // NG
// V := ClsC.FStrictProtected.Value; // NG
V := ClsC.FProtected.Value;
V := ClsC.FPublic.Value;
V := ClsC.FPublished.Value;
except
end;
finally
ClsC.Free;
end;
end; { DummyU2 }
{ TClsC }
procedure TClsC.Dummy;
var
V: Integer;
begin
// --------------------------------------
// Unit1.TClsA, Unit2.TClsC(継承)
// Unit2.TClsC.Self <- アクセス
// --------------------------------------
//V := Self.FStrictPrivate.Value; // NG
//V := Self.FPrivate.Value; // NG
V := Self.FStrictProtected.Value;
V := Self.FProtected.Value;
V := Self.FPublic.Value;
V := Self.FPublished.Value;
end;
end.
6.3. Delphi のクラス参照型 (メタクラス)
クラスのインスタンス (オブジェクト) へのポインタはクラス型の変数です。クラス参照型 (メタクラス) 6 はクラス型そのものに対するポインタです。
クラス参照型は型宣言部 (type) にて "型名 = class of 対象クラス型;" として定義します。次のようにしてクラス参照型を定義できます。
type
TObjectClass = class of TObject;
考え方はポインタ型と同じです。
type
TMyClass = class
function FuncA: Integer;
class function FuncB: Integer;
end;
MyC = class of TMyClass; // TMyClass のクラス参照型
function TMyClass.FuncA: Integer;
begin
...
end;
class function TMyClass.FuncB: Integer;
begin
...
end;
var
MyClass: TMyClass;
v: Integer;
begin
MyClass := TMyClass.Create; // <- クラス参照でコンストラクタが呼び出されている
v := MyClass.FuncA; // オブジェクト参照
v := TMyClass.FuncB; // クラス参照
v := MyC.FuncB; // クラス参照型を使ったクラス参照
...
MyClass は TMyClass のオブジェクトです。正確には TMyClass のインスタンスへのポインタです。 FuncA はオブジェクト参照で呼び出されています。コード中の FuncB は TMyClass のクラスメソッドなのでクラス参照で呼び出されています。
クラスメソッドはクラス参照だけでなく、オブジェクト参照でも呼び出す事ができます。
コンストラクタは通常、クラス参照で呼び出されます。コンストラクタをオブジェクト参照で呼び出した場合、オブジェクト (インスタンス) は生成されず、通常のメソッドとして実行されます。
See also:
6.4. Delphi のインターフェイス型
(オブジェクト)インターフェイスはクラスに実装させることができるメソッドを定義します。インターフェイスはクラスと同じように宣言しますが、直接インスタンス化することはできません。
インターフェイス型は Delphi 3 で実装され、Delphi 6 で汎用的な IInterface (以前は IUnknown) が使えるようになりました。また、インターフェイスを使うと多重継承に似た事ができます。インターフェイス型もまた構造化型です。
See also:
6.4.1. インターフェイス型の定義
インターフェイス型は型宣言部 (type) にて "型名 = interface (親インターフェイス) ['GUID'] ~ end;" として定義します。
次のようにしてインターフェイス型を定義できます。GUID は Delphi のコードエディタで〔Ctrl〕+〔Shift〕+〔G〕で生成できます。インターフェイス型の親インターフェイスを省略するとルートインターフェイス IInterface から派生します。
type
IItfA = interface
['{xxxxxxxx-6953-4C6B-B1E3-DBB2E7419162}']
function FuncA: string;
end;
IItfB = interface(IItfA)
['{xxxxxxxx-261D-4742-BC7E-8D05B22D8016}']
function FuncB: string;
end;
6.4.2. インターフェイス型を使ったクラス
インターフェイスを使ったクラスは基本的に TInterfacedObject (またはその下位クラス) から派生します。IItfB を使ったクラスの実装例を次に示します。
type
TCls = class (TInterfacedObject, IItfB)
function FuncA: string;
function FuncB: string;
end;
function TCls.FuncA: string;
begin
result := 'FuncA';
end;
function TCls.FuncB: string;
begin
result := 'FuncB';
end;
このクラスを使ってみます。
var
Cls: TCls;
begin
Cls := TCls.Create;
try
Writeln(Cls.FuncA);
Writeln(Cls.FuncB);
finally
Cls.Free;
end;
Readln;
end.
実行結果は次の通りです。
FuncA
FuncB
クラス型変数ではなくインターフェイス型変数を使うと参照カウントが行われるようになり、Free での破棄が不要になります。
var
Cls: IItfB; // <- インターフェイス型変数を使う
begin
ReportMemoryReakOnShutdown := True; // アプリケーション終了時にメモリリークを報告する
Cls := TCls.Create;
Writeln(Cls.FuncA);
Writeln(Cls.FuncB);
Readln;
end.
See also:
- インターフェイス参照 (DocWiki)
- Delphi の Interface (.delphi maniacs)
- インターフェース使っててハマりそうなところをつらつらと (Qiita:ktz_alias)
- Delphiでインターフェースを使う (偏った言語信者の垂れ流し)
6.5. Delphi の抽象クラス型
Delphi 2005 以降では次のようにして抽象クラス型を定義できます。
type
TCls = class abstract (TObject) { TObject を継承した抽象クラス型 TCls の定義 }
end;
...なのですが、何故か抽象クラス型をインスタンス化できてしまい、エラーも警告も出ません。つまり abstract の指定はマーカーとしての意味しかありません。
abstract を指定していなくても抽象メソッドが含まれていれば抽象クラスになります。こちらもインスタンス化できてしまうのですが、コンパイラが警告 W1020 を吐きます。
次のようなコンパイラ指令を書いておけば警告をエラーに昇格できるため、抽象メソッドを含むクラスのインスタンス化は阻止する事ができます。
{$WARN CONSTRUCTING_ABSTRACT ERROR}
なお、abstract の代わりに sealed を指定すると継承できないクラス (シールドクラス/ファイナルクラス) を作る事ができます。こちらの方は継承しようとするとちゃんとエラーになります...謎です。
6.6. Delphi の高度なレコード型 (Advanced Record)
Delphi 2006 からレコード型にメソッドやプロパティ、コンストラクタを持たせられるようになりました。次のコードは ObjTest.dpr
の高度なレコード型版です。
program RecTest;
{$APPTYPE CONSOLE}
type
TRec = record
private
FValue: Integer;
public
constructor Create(InitialValue: Integer);
procedure Destroy;
function Multiply(n: Integer): Integer;
property Value: Integer read FValue write FValue;
end;
PRec = ^TRec;
{ TRec }
constructor TRec.Create(InitialValue: Integer);
begin
FValue := InitialValue;
end; { TRec.Init }
procedure TRec.Destroy;
begin
;
end; { TRec.Destroy }
function TRec.Multiply(n: Integer): Integer;
begin
result := FValue * n
end; { TRec.Multiply }
var
sRec: TRec;
dRec: PRec;
begin
// Static (1)
sRec.Value := 3;
Writeln(sRec.Multiply(5));
// Static (2)
sRec := sRec.Create(3);
Writeln(sRec.Multiply(5));
// Static (3)
sRec.Create(3);
Writeln(sRec.Multiply(5));
// Dynamic
dRec := New(PRec, Create(0));
try
dRec^.Value := 7;
Writeln(dRec^.Multiply(9));
dRec^.Destroy;
finally
Dispose(dRec);
end;
Readln;
end. { Main }
オブジェクト型とほぼ同じような使い方ができるようになっています。メインブロック中の ^
を取り除いても動作します 3。Destroy() がデストラクタではなくただのメソッドになっている事に注意してください。
- コンストラクタには最低でも一つのパラメータが必要で、初期値を持つパラメータは初期値が指定されない可能性がある (内部で使っている引数なしのコンストラクタとカブる) ため、使用する事ができません。
- デストラクタはありません。
- レコードなので継承はできません。
- レコードなので可変部は普通に使えます。
サンプルコードの (2)
の所は、クラスのように書いてはいけないのでしょうか?
// Static (2)
sRec := TRec.Create(3);
Writeln(sRec.Multiply(5));
書けるのは書けるのですが、この処理は、
- TRec 型の (静的な) 変数 sRec が作られる。
- 無名の TRec 型動的変数が作られる。
- sRec に動的変数がコピーされる。
となってしまいます (一時的に TRec 型の変数が 2 つ存在する) のでオススメしません。
See also:
6.7. カスタム管理レコード型 (Custom Managed Records)
Delphi 10.4 Sydney からコンストラクタやデストラクタのような働きをする演算子によって、初期化時と終了時の処理を行う事ができるようになりました。例を挙げます。
program CustomManagegRecordTest;
{$APPTYPE CONSOLE}
type
TMyRecord = record
Value: Integer;
class operator Initialize(out Dest: TMyRecord);
class operator Finalize(var Dest: TMyRecord);
end;
{ TMyRecord }
class operator TMyRecord.Initialize(out Dest: TMyRecord);
begin
Dest.Value := 10;
Writeln('Start!');
end;
class operator TMyRecord.Finalize(var Dest: TMyRecord);
begin
Writeln('Done.');
end;
begin
begin
var Rec: TMyRecord;
Writeln(Rec.Value);
end;
Readln;
end.
カスタム管理レコード型 (TMyRecord) である Rec を空ブロックの中で使っています 7。これの実行結果は次のようになります。
Start!
10
Done.
コンストラクタやデストラクタ (ありませんけど) を明示的に呼び出さなくても、初期化コードと終了時コードが実行されます。
演算子 | 説明 |
---|---|
Initialize | 初期化処理を行います |
Finalize | 終了時処理を行います |
See also:
- カスタム管理レコード (DocWiki)
- Delphi 10.4の新機能: カスタム マネージド レコード (Embarcadero Blogs)
- Custom Managed Records Coming in Delphi 10.3 (Marco Tech Blog) - 10.3 で実装されるハズだった時の仕様
- [Delphi] カスタム管理レコードを使ったスマートポインタ (Qiita: @pik)
6.7.1. 代入とコピー
カスタム管理レコード型は 継承できない (静的な) オブジェクト型のようなもの という表現がしっくりくるでしょうか。
それでも、レコード型には変わりないので、代入はコピーとなります。ポインタや参照の代入ではありません。
...
begin
begin
var Rec1: TMyRecord;
var Rec2: TMyRecord;
Rec1.Value := 11;
Rec2 := Rec1;
Rec1.Value := 10;
Writeln(Rec1.Value);
Writeln(Rec2.Value);
end;
Readln;
end.
結果は次のようになります。
Start!
Start!
10
11
Done.
Done.
初期化処理と終了時処理が 2 つ分行われています。
6.7.2. Assign 演算子
Assign 演算子を使うと、代入時の挙動もカスタマイズできます。
演算子 | 説明 |
---|---|
Assign | 代入時の処理を行います |
次に例を挙げます。
program CustomManagegRecordTest;
{$APPTYPE CONSOLE}
type
TMyRecord = record
Value: Integer;
class operator Initialize(out Dest: TMyRecord);
class operator Finalize(var Dest: TMyRecord);
class operator Assign (var Dest: TMyRecord; const [ref] Src: TMyRecord);
end;
{ TMyRecord }
class operator TMyRecord.Initialize(out Dest: TMyRecord);
begin
Dest.Value := 10;
Writeln('Start!');
end;
class operator TMyRecord.Finalize(var Dest: TMyRecord);
begin
Writeln('Done.');
end;
class operator TMyRecord.Assign (var Dest: TMyRecord; const [ref] Src: TMyRecord);
begin
Dest.Value := Src.Value * 2; // ニヴァイ
Writeln('Multiply!');
end;
begin
var Rec1: TMyRecord;
var Rec2: TMyRecord;
Rec1.Value := 11;
Rec2 := Rec1;
Rec1.Value := 10;
Writeln(Rec1.Value);
Writeln(Rec2.Value);
Readln;
end.
実行結果は次のようになります。
Start!
Start!
Multiply!
10
22
Done.
Done.
6.7.3. コンストラクタと Intialize 演算子の併用
コンストラクタと Initialize 演算子を併用するとどうなるのでしょう?
program CustomManagegRecordTest;
{$APPTYPE CONSOLE}
type
TMyRecord = record
Value: Integer;
constructor Create(InitialValue: Integer);
class operator Initialize(out Dest: TMyRecord);
class operator Finalize(var Dest: TMyRecord);
end;
{ TMyRecord }
constructor TMyRecord.Create(InitialValue: Integer);
begin
Self.Value := InitialValue;
Writeln('Begin!');
end;
class operator TMyRecord.Initialize(out Dest: TMyRecord);
begin
Dest.Value := 10;
Writeln('Start!');
end;
class operator TMyRecord.Finalize(var Dest: TMyRecord);
begin
Writeln('Done.');
end;
begin
with TMyRecord.Create(3) do
Writeln(Value);
Readln;
end.
結果はこうなりました。
Start!
Begin!
3
Done.
イニシャライザが先に走るのですね。
6.8. Delphi のヘルパー
Delphi にはヘルパーと呼ばれる機能があります。オブジェクトを継承せずに機能を拡張するもので、大別すると次の 3 種類があります。
- クラスヘルパー
- レコードヘルパー
- レコードヘルパー (組み込み型用)
クラスヘルパーとレコードヘルパーは Delphi 2006 から利用可能でしたが、真価を発揮するのは Delphi 2009 以降です。XE4 以降では Integer 等のオブジェクトではない組み込み型に対してもヘルパーを作用させる事ができるようになっています。
See also:
- クラス ヘルパとレコード ヘルパ(Delphi) (DocWiki)
- Delphi の型をレコードヘルパで拡張する (Qiita)
- 【Delphi】クラスヘルパによる private メンバアクセスの件を with 文で回避できると聞いて (Qiita)
6.9. Delphi のレコード型、オブジェクト型、クラス型、インターフェイス型の主な違い
Delphi でのレコード型、オブジェクト型、クラス型の主な違いは次の通りです。
レコード型 | レコード型 (高度) |
レコード型 (カスタム管理) |
オブジェクト型 | クラス型 | インターフェイス型 | |
---|---|---|---|---|---|---|
定義 | record | record | record | object | class | interface |
継承 | × | × | × | 〇 | 〇 | 〇 |
フィールド | 〇 | 〇 | 〇 | 〇 | 〇 | × |
可変部 | 〇 | 〇 | 〇 | × | × | × |
メソッド | × | 〇 | 〇 | 〇 | 〇 | 〇 |
プロパティ | × | 〇 | 〇 | △ 8 | 〇 | 〇 |
可視性指定子 | × | △ 9 | △ 9 | 〇 | 〇 | × |
コンストラクタ | × | △ 10 | △ 11 | 〇 | 〇 | × |
デストラクタ | × | × | △ 12 | 〇 | 〇 | × |
6.10. クラスに関連する用語
言語によってクラスに関連する用語に違いがあります。同じものを指しているのに、日本語訳された時に用語がゆらいでいるものもあります。
言語 | ルートクラス | クラス | スーパークラス | サブクラス | メッセージ |
---|---|---|---|---|---|
Delphi | TObject | クラス (Class) |
直接上位 (Immediate Ancestor) |
直接下位 (Immediate Descendant) |
メソッド呼び出し (Method Call) |
Turbo Pascal | Object | オブジェクト型 (Object Type) |
直系上位 (Immediate Ancestor) |
直系下位 (Immediate Descendant) |
メソッド呼び出し (Method Call) |
Object Pascal (Apple) |
TObject | オブジェクト型 (Object Type) |
直系のアンセスタ (先祖) (Immediate Ancestor) |
直系のディセンダント (子孫) (Immediate Descendant) |
メソッド呼び出し (Method Call) |
Clascal | TObject | クラス (Class) |
スーパークラス (Superclass) |
サブクラス (Subclass) |
メソッド呼び出し (Method Call) |
Smalltalk | Object | クラス (Class) |
スーパークラス (Superclass) |
サブクラス (Subclass) |
メッセージ (message) |
- Object Pascal (Apple) と Turbo Pascal ではクラスの事をオブジェクト型と呼んでいます。
- Delphi のオブジェクト型は Turbo Pascal のオブジェクト型です。
- Delphi ではオブジェクト型とは別にクラス型があります。
- Delphi には Smalltalk の Message に概念のよく似た
メッセージメソッド
があります。
See also:
参考文献
Object Pascal Handbook
タイトル | 著者 | ISBN-10 (Amazon) |
出版年 |
---|---|---|---|
Object Pascal Handbook | マルコ・カントゥ (著) | 1514349949 | 2015/8/5 |
Object Pascal Handbook | マルコ・カントゥ (著) 藤井 等 (訳) |
487783401X | 2016/6/10 |
Object Pascal Handbook Delphi 10.4 Sydney Edition |
マルコ・カントゥ (著) | B08XZ44KXH | 2021/3/3 |
Object Pascal Handbook Delphi 11 Alexandria Edition |
マルコ・カントゥ (著) 藤井 等 (訳) |
4877835210 | 2022/4/10 |
最近の Delphi の文法はこれと DocWiki があればいいかと。英語版でよければ PDF を無償 DL できます。
- Object Pascal Handbook 英語版 (Embarcadero)
- Object Pascal Handbook Delphi 10.4 Sydney Edition (Embarcadero)
- Object Pascal Handbook Delphi 11.0 Alexandria Edition (Embarcadero)
- OBJECT PASCAL HANDBOOK に掲載のソースコード (GitHub)
- Object Pascal Handbook Delphi 10.4 Sydney Edition / 11.0 Alexandria Edition に掲載のソースコード (GitHub)
- DocWiki (Embarcadero)
DELPHI クイックリファレンス
タイトル | 著者 | ISBN-10 (Amazon) |
出版年 |
---|---|---|---|
Delphi in a Nutshell: A Desktop Quick Reference | レイ・リシュナー (著) | 1565926595 | 2000/3/26 |
DELPHI クイックリファレンス | レイ・リシュナー (著) 光田 秀 (訳) 竹田 知生 (訳) |
4873110408 | 2001/5/24 |
Delphi 5 時点の書籍ですが、Delphi の基本的な部分...言語仕様や組み込みルーチンに絞って書かれたものなので、かなりの部分が最新版の Delphi でも通用すると思います。
逆に言えば VCL 等のライブラリには一切触れられていないという事ですから、その点には注意が必要です。
- DELPHI クイックリファレンスに掲載のソースコード (ftp.oreilly.com)
- Delphi in a Nutshell に掲載のソースコード (resources.oreilly.com)
- Delphi in a Nutshell 正誤表 (oreilly.com)
Object Pascal Language Guide
Delphi 1.0 で加えられた変更を知る方法ですが、Delphi 2~4 の CD-ROM を持っているのなら DELPHI16\EXTRAS\MANUALS\
にある "Object Pascal Language Guide (OBJLANG.PDF)"
を参照してみてください。紙マニュアルやヘルプ (WinHelp) に書かれている事と同じですが、視認性はいいと思います。
[ ← 5. (標準) Pascal へのオブジェクト指向拡張 ] [ ↑ 目次へ ]
-
Delphi 1 では行コメントが使えません。行コメントが使えるのは Delphi 2 以降です。 ↩
-
「下位互換性のために残してある」と言いながらも Delphi, Delphi 2 で拡張が行われており、例えば下にある
ObjTest.dpr
はプロパティが使われているために Delphi 1 ではコンパイルできません。 ↩ -
ARC は Delphi 10.4 Sydney で廃止されました。 ↩
-
Delphi 1 では
オブジェクト参照型
と呼ばれていました。とても紛らわしいネーミングです。 ↩ -
空ブロックを使わないと、インライン宣言した変数の寿命は Readln() の後になります。 ↩
-
Delphi 2 以降でプロパティが使えます。 ↩
-
1 つ以上のパラメータを持つ必要があります。 ↩
-
コンストラクタと似たような働きをする Initialize 演算子があります。 ↩
-
デストラクタと似たような働きをする Finalize 演算子があります。 ↩