8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

DelphiAdvent Calendar 2019

Day 6

<4> Turbo Pascal のオブジェクト指向拡張 (Pascal へのオブジェクト指向拡張の歴史と Delphi)

Last updated at Posted at 2019-12-05

4. Turbo Pascal のオブジェクト指向拡張

Borland は 1989 年の Turbo Pascal バージョン 5.5 において、オブジェクト指向拡張を取り入れました。自社の Pascal に対して行った最初のオブジェクト指向拡張です。

これが Delphi に繋がる (Borland の) Object Pascal の始まりとなるのですが、Borland 自身はこの拡張を Object Pascal とは呼んでいません。オブジェクト指向拡張を強調する文脈では Pascal with Objects や、単に オブジェクト指向拡張 (Object-Oriented Extensions) と呼んでいました 1
image.png
Turbo Pascal 5.5 のオブジェクト指向拡張は 1985 年にラリー・テスラーが書いた "Object Pascal Report"2 3 と、同じく 1985 年にビャーネ・ストラウストラップが書いた "The C++ Programming Language" を元に行われています。
image.png
この事は「Turbo Pascal 5.5 オブジェクト指向プログラミングガイド」の前書きに記載されています。

The object-oriented extensions in Turbo Pascal 5.5 were inspired by Larry Tesler's "Object Pascal Report" (Apple, 1985) and Bjarne Stroustrup's "The C++ Programming Language" (1986, Addison-Wesley).

See also:

4.1. Turbo Pascal のオブジェクト型

Turbo Pascal のオブジェクト指向拡張は オブジェクト(型) によって行われています。Borland はオブジェクト型の事をクラスとは呼んでいません。Apple の Object Pascal に倣った感じです。

オブジェクト型は型宣言部 (type) にて "型名 = objectend;" で定義します。

type
  TObj = object { Object 型 TObj の定義 }
    FID: Integer;
    FFirstName: string;
    FLastName: string;
  end;

ここまではレコード型とほぼ同じですが、オブジェクト型は継承ができます (多重継承はできません)。

type
  TObjEx = object(TObj) { TObj を継承した TObjEx 型の定義 }
    ...
  end;  

オブジェクト型では、継承元の存在しないルートオブジェクト (ルートクラスに相当するもの) を作る事が可能です。

4.1.1. (静的な) オブジェクト型

オブジェクト型は以下のようにして使うことができます。

ObjTest1.pas
program ObjTest1;

type
  TObj = object
    FID: Integer;
    FFirstName: string;
    FLastName: string;
  end; { TObj }
  
  TObjEx = object(TObj)
  end; { TObjEx }
  
var
  ObjEx: TObjEx; { オブジェクト型変数の宣言 }
  
begin
  ObjEx.FID := 100;
  ObjEx.FFirstName := 'Hello,';
  ObjEx.FLastName  := 'world.';
  writeln(ObjEx.FID       );
  writeln(ObjEx.FFirstName);
  writeln(ObjEx.FLastName );  
end.

変数 ObjEx は TObjEx 型のインスタンスです。

識別子 意味
TObj オブジェクト型
(ルートオブジェクト)
TObjEx オブジェクト型
ObjEx TObj 型の変数
  • 型定義部 (type) で TObj というオブジェクト型が定義されている。
  • 型定義部 (type) で TObjEx というオブジェクト型が定義されている。
  • 変数宣言部 (var) で ObjEx という TObjEx オブジェクト型が宣言されている。

オブジェクト型はレコード型と異なりメソッドも使えます。

program ObjTest1;

type
  TObj = object
    FID: Integer;
    FFirstName: string;
    FLastName: string;
    function GetName: string;
  end; { TObj }
  
  TObjEx = object(TObj)
  end; { TObjEx }

function TObj.GetName: string;
begin
  GetName := FFirstName + FLastName;
end;
  
var
  ObjEx: TObjEx;
  
begin
  ObjEx.FID := 100;
  ObjEx.FFirstName := 'Hello,';
  ObjEx.FLastName  := 'world.';
  writeln(ObjEx.FID       );
  writeln(ObjEx.GetName   );  
end.

標準 Pascal のレコード型と Turbo Pascal のオブジェクト型の主な違いは次の通りです。

レコード型 オブジェクト型
定義 record object
継承 ×
フィールド
可変部 ×
メソッド ×
プロパティ × × 4
可視性指定子 × 5
コンストラクタ ×
デストラクタ ×

4.1.2. 動的なオブジェクト型

レコード型とやり方は同じです。

ObjTest2.pas
program ObjTest2;

type
  TObj = object
    FID: Integer;
    FFirstName: string;
    FLastName: string;
    function GetName: string;
  end; { TObj }
  
  TObjEx = object(TObj)
  end; { TObjEx }
  PObjEx = ^TObjEx; { ポインタ型の定義 }

function TObj.GetName: string;
begin
  GetName := FFirstName + FLastName;
end;
  
var
  ObjEx: PObjEx; { ポインタ型変数の宣言 }
  
begin
  New(ObjEx); { 動的変数用メモリの確保と識別値の割り当て }

 { 動的変数を逆参照してアクセス }
  ObjEx^.FID := 100;
  ObjEx^.FFirstName := 'Hello,';
  ObjEx^.FLastName  := 'world.';
  writeln(ObjEx^.FID       );
  writeln(ObjEx^.GetName   );

  Dispose(ObjEx); { 識別値が指す動的変数用メモリの解放 }
end.

上記例の場合、ObjEx は TObjEx 型のポインタ変数で、ObjEx^ のようにキャレット記号 (^) を使って動的変数を逆参照しています。動的変数はオブジェクトであり、TObjEx 型のインスタンスです。標準 Pascal の用語で詳細を説明すると次のようになります。

識別子 意味
TObj オブジェクト型
(ルートオブジェクト)
TObjEx オブジェクト型 (対象型)
PObjEx ポインタ型
ObjEx ポインタ型変数
ObjEx^ TObjEx 型の動的変数 (対象変数)
  • 型定義部 (type) で TObj, TObjEx というオブジェクト型が定義されている。
  • 型定義部 (type) で TObjEx を対象型とするポインタ型 PObjEx が定義されている。
  • 変数宣言部 (var) で ObjEx という PObjEx ポインタ型が宣言されている。
  • New() で TObjEx 型の動的変数 (対象変数) 用メモリが確保され、動的変数を指し示す識別値 (ポインタ値) がポインタ型変数 PObjEx に格納される。
  • ポインタ型変数 PObjEx に格納されている識別値 (ポインタ値) から動的変数 (対象変数)逆参照するには PObjEx^ のようにキャレット記号 (逆参照演算子) を使う。
  • PObjEx に格納されている識別値 (ポインタ値) が指し示す TObjEx 型の動的変数 (対象変数) が使っていたメモリは Dispose() で解放される。

Turbo Pascal のオブジェクト型は型である (オブジェクト型自体がオブジェクトで構成されていない) ため、用語の意味は次のようになります。

用語 意味
オブジェクト型 type 型 = object ~ で定義された型の事
インスタンス 静的なオブジェクト型: オブジェクト型の変数
動的なオブジェクト型: オブジェクト型の動的変数
オブジェクト オブジェクト型のインスタンスの事

オブジェクト型ではコンストラクタとデストラクタが使えます。コンストラクタやデストラクタの名前は任意ですが、それぞれ InitDone が推奨されています。

ObjTest3.pas
program ObjTest3;

type
  TObj = object
    FID: Integer;
    FFirstName: string;
    FLastName: string;
    function GetName: string;
  end; { TObj }
  
  TObjEx = object(TObj)
    constructor Init;
    destructor Done; virtual;
  end; { TObjEx }
  PObjEx = ^TObjEx;

function TObj.GetName: string;
begin
  GetName := FFirstName + FLastName;
end;

constructor TObjEx.Init;
begin
  FID := 123;
  FFirstName := 'Blaise';
  FLastName  := 'Pascal';
end; 

destructor TObjEx.Done;
begin
end;
  
var
  ObjEx1: TObjEx;
  ObjEx2: PObjEx;
  
begin
  writeln(ObjEx1.FID);

  New(ObjEx2, Init);     // オブジェクトの生成と初期化処理
  writeln(ObjEx2^.FID);
  Dispose(ObjEx2, Done); // 終了処理とオブジェクトの破棄 
end.

ただし、コンストラクタやデストラクタは明示的に呼ぶ必要があります。インスタンス化の際にコンストラクタは呼ばれませんし、破棄時にデストラクタが呼ばれることもありません。上記例を実行すると次のような結果になります。

0
123

New() と Dispose() が拡張され、第 2 パラメータにオブジェクト型のコンストラクタ呼び出しとデストラクタ呼び出しを指定できるようになっています。次のコードとほぼ同じとなりますが、同等ではありません。

  // オブジェクトの生成と初期化処理
  New(ObjEx2);   // インスタンス化
  ObjEx2.Init;

  // 終了処理とオブジェクトの破棄
  ObjEx2.Done;
  Dispose(ObjEx2);  

メモリの解放を正確に行うためにはデストラクタ呼び出しをパラメータに取る Dispose() を実行する必要があります。見た目には空のデストラクタであっても、コンパイラは正しいクリーンナップコードを出力します。

New() は関数としても実装されており、次のコードは、

  New(ObjEx2, Init); 
  ...
  Dispose(ObjEx2, Done);  

このようにも書けます。

  ObjEx2 := New(PObjEx, Init);
  ...
  Dispose(ObjEx2, Done);  

この時、New() の最初のパラメータにはオブジェクト型を対象型とするポインタ型を指定します。第 2 パラメータにはコンストラクタ呼び出しを指定できます。

仮想メソッド (virtual) を持つオブジェクト型はコンストラクタを実装する必要があり、仮想メソッドを呼ぶ前にコンストラクタを呼ぶ必要があります。

4.1.3. VMT と TypeOf()

オブジェクトは次のいずれかの条件を満たすとバーチャルメソッドテーブル (VMT) と呼ばれる特殊なフィールドを含むようになります。

  • 仮想メソッドを持つ
  • コンストラクタを持つ
  • デストラクタを持つ
  • ルートオブジェクトではない (継承したオブジェクトである)

標準関数 TypeOf() はオブジェクト型の VMT へのポインタを返すため、オブジェクト型の判断に使う事ができます。

See also:

4.2. Turbo Pascal の入手方法

Turbo Pascal のいくつかのバージョンは、現在でもアンティークソフトウェアとして Embarcadero から無償で入手できます。

バージョン 説明
Turbo Pascal 1.0 最初の Turbo Pascal
Turbo Pascal 3.02 8087 サポート、BCD 対応
Turbo Pascal 5.5 オブジェクト指向拡張

すべて MS-DOS 版です。64bit Windows だとそのままでは動作しないので、DOSBox(-X) 等で動作させるといいでしょう。

See also:

4.3. Free Pascal Compiler (FPC)

Free Pascal (FPC) はオープンソースの Object Pascal コンパイラです。Turbo Pascal のようなテキストベースの IDE が付属します。
image.png
多くのプラットフォームで動作し、GUI ベースの Lazarus という IDE もあります (Lazarus には FPC が含まれています)。
image.png
元々は Turbo Pascal 互換を目指して作られていましたが、後に Delphi 互換を含め、様々な互換モードを実装するようになりました。

See also:

4.4. Microsoft Quick Pascal

Microsoft の Quick Pascal は Turbo Pascal 5.5 とほぼ同時期の 1989/05 にリリースされています。

image.png

  • Turbo Pascal 4.0 互換 (5.0 互換?)
  • それまでの Microsoft Pascal とは別系統 (仏 Nat System からのライセンス供与)
  • Apple のオブジェクト指向拡張を導入
  • Turbo Pascal 5.5 のオブジェクト指向拡張とは互換性がない
  • マウス対応 (TP は 6.0 から)
  • マルチウィンドウ対応 (TP は 6.0 から)
  • 構文強調表示対応 (TP は 7.0 から)

See also:

参考文献

image.png

タイトル 著者 ISBN-10
(Amazon)
出版年
Turbo Pascal 5.5
オブジェクト指向プログラミングガイド
Borland International (著)
(株)ボーランドジャパン (訳)
--- 1989/12/20

オークションなどで見かけたら確保しておくといいかもしれません。第一章だけでよければ英語の PDF が Embarcadero の サイトから DL できます。

See also:

索引

[ ← 3. Machintosh 用 Pascal のオブジェクト指向拡張 ] [ ↑ 目次へ ] [ → 5. (標準) Pascal へのオブジェクト指向拡張 ]

  1. "C with Classes" (C++ は当初こう呼ばれていた) のオマージュだと思われます。

  2. "Object Pascal Report", Structured Programming (Structured Language World) 9, 3 (1985), pp. 10-15.

  3. "Object Pascal Report", Apple Technical Report No.1 (1985)

  4. Delphi 2 以降ではオブジェクト型にもプロパティが使えます。

  5. Turbo Pascal 7.0 以降で privatepublic が、Delphi では加えて protected も使えます。published は使えません。

8
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?