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

# 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](https://qiita-image-store.s3.amazonaws.com/0/21785/353a6748-f71d-e938-b64f-441952c31455.png)
Turbo Pascal 5.5 のオブジェクト指向拡張は 1985 年に[ラリー・テスラー](https://ja.wikipedia.org/wiki/%E3%83%A9%E3%83%AA%E3%83%BC%E3%83%BB%E3%83%86%E3%82%B9%E3%83%A9%E3%83%BC)が書いた **"Object Pascal Report"**[^2] [^5] と、同じく 1985 年に[ビャーネ・ストラウストラップ](https://ja.wikipedia.org/wiki/%E3%83%93%E3%83%A3%E3%83%BC%E3%83%8D%E3%83%BB%E3%82%B9%E3%83%88%E3%83%AD%E3%83%B4%E3%82%B9%E3%83%88%E3%83%AB%E3%83%83%E3%83%97)が書いた **"The C++ Programming Language"** を元に行われています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/4b055dee-74dd-fcc5-93ea-28673cdd3c42.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:**

 - [Turbo Pascal (Wikipedia)](https://ja.wikipedia.org/wiki/Turbo_Pascal)
 - [Turbo Pascal (Wikipedia:En)](https://en.wikipedia.org/wiki/Turbo_Pascal)
 - [Turbo Vision (Wikipedia:En)](https://en.wikipedia.org/wiki/Turbo_Vision)
 - [Object Windows Library (Wikipedia:En)](https://en.wikipedia.org/wiki/Object_Windows_Library)

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

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

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

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

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

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

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

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

```pascal: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 | オブジェクト型<br> (ルートオブジェクト) |
| TObjEx | オブジェクト型 |
| ObjEx | TObj 型の変数|

 - 型定義部 (**type**) で TObj というオブジェクト型が定義されている。
 - 型定義部 (**type**) で TObjEx というオブジェクト型が定義されている。
 - 変数宣言部 (**var**) で ObjEx という TObjEx オブジェクト型が宣言されている。

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

```pascal
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** |
| 継承 | × | 〇 |
| フィールド | 〇 | 〇 |
| 可変部 | 〇  | × |
| メソッド | × | 〇 |
| プロパティ | × | × [^3] |
| 可視性指定子 | × | △ [^4]|
| コンストラクタ | × | 〇 |
| デストラクタ | × | 〇 |


### 4.1.2. 動的なオブジェクト型
レコード型とやり方は同じです。

```pascal: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 | オブジェクト型<br> (ルートオブジェクト) |
| 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** ～ で定義された型の事 |
| インスタンス | 静的なオブジェクト型: オブジェクト型の変数<br>動的なオブジェクト型: オブジェクト型の動的変数 |
| オブジェクト | オブジェクト型のインスタンスの事 |

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

```pascal: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 パラメータにオブジェクト型のコンストラクタ呼び出しとデストラクタ呼び出しを指定できるようになっています。次のコードとほぼ同じとなりますが、同等ではありません。

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

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

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

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

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

このようにも書けます。

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

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

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

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

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

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

**See also:**

 - [System.TypeOf (DocWiki)](http://docwiki.embarcadero.com/Libraries/ja/System.TypeOf)
 - [E2082 TYPEOF は VMT を持つオブジェクト型に対してのみ使用することができます (Delphi) (DocWiki)](http://docwiki.embarcadero.com/RADStudio/ja/E2082_TYPEOF_%E3%81%AF_VMT_%E3%82%92%E6%8C%81%E3%81%A4%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E5%9E%8B%E3%81%AB%E5%AF%BE%E3%81%97%E3%81%A6%E3%81%AE%E3%81%BF%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E3%81%93%E3%81%A8%E3%81%8C%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99_(Delphi))

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

| バージョン | 説明 |
|:--|:--|
| [Turbo Pascal 1.0](https://cc.embarcadero.com/Item/26017) | 最初の Turbo Pascal |
| [Turbo Pascal 3.02](https://cc.embarcadero.com/Item/26016)  | 8087 サポート、BCD 対応 |
| [Turbo Pascal 5.5](https://cc.embarcadero.com/Item/26015)  | オブジェクト指向拡張 | 

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

**See also:**

 - [Pascal の勉強に使えそうな Pascal 処理系 (Qiita)](https://qiita.com/ht_deko/items/6376997a6d74e77c89e3)
 - [DOSBox](https://www.dosbox.com/)
 - [DOSBox-X (GitHub)](https://github.com/joncampbell123/dosbox-x/releases)
 - [Turbo Pascal 1.0 を Windows 10 (64bit) / 11 にインストールしてみる](https://qiita.com/ht_deko/items/54cefe48e729742e818d)
 - [Turbo Pascal 3.02 を Windows 10 (64bit) / 11 にインストールしてみる](https://qiita.com/ht_deko/items/03f5f7ee0893402f99f6)
 - [Turbo Pascal 5.5 を Windows 10 (64bit) / 11 にインストールしてみる](https://qiita.com/ht_deko/items/eb35e0480559f893a9b8)

## 4.3. Free Pascal Compiler (FPC)
Free Pascal (FPC) はオープンソースの Object Pascal コンパイラです。Turbo Pascal のようなテキストベースの IDE が付属します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/eb8f0fcb-d4e2-ac32-a8bd-f38527dfedc3.png)
多くのプラットフォームで動作し、GUI ベースの **Lazarus** という IDE もあります (Lazarus には FPC が含まれています)。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/1d83c3e7-df64-f7bb-8bb7-f051c8c8c52d.png)
元々は Turbo Pascal 互換を目指して作られていましたが、後に Delphi 互換を含め、様々な互換モードを実装するようになりました。

**See also:**
 - [Free Pascal (freepascal.org)](https://www.freepascal.org/)
 - [Lazarus (lazarus-ide.org)](https://www.lazarus-ide.org/)


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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/c551b78d-5e5a-5399-89d6-381a9a25552c.png)

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

**See also:**
 - [Microsoft Pascal / Quick Pascal (Wikipedia: en)](https://en.wikipedia.org/wiki/Microsoft_Pascal)
 - [Quick Pascal (EDM/2)](http://www.edm2.com/index.php/QuickPascal)

# 参考文献
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/ef7dd428-52b5-1d64-6a8d-1366a890aa5f.png)

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

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

**See also:**

 - [Turbo Pascal 5.5 Object-Oriented Programming Guide (Embarcadero)](http://edn.embarcadero.com/jp/article/images/20803/TP_55_OOP_Guide.pdf)
 - [Turbo Pascal 5.5 Object-Oriented Programming Guide (Internet Archive)](https://web.archive.org/web/20210605060839/https://edn.embarcadero.com/jp/article/images/20803/TP_55_OOP_Guide.pdf)
 - [技術評論社の Software Technology シリーズから Pascal 関連の書籍を読んでみる (Qiita)](https://qiita.com/ht_deko/items/06946a72b51f577523bb)
 - [技術評論社の Software Technology シリーズから Pascal 関連の書籍を読んでみる <番外編> (Qiita)](https://qiita.com/ht_deko/items/2f5ecd6858b8d4eaab49)

# 索引
[ [← 3. Machintosh 用 Pascal のオブジェクト指向拡張](https://qiita.com/ht_deko/items/cd245180363e1911afa7) ] [ [↑ 目次へ](https://qiita.com/ht_deko/items/ff2d90c9174290583377) ] [ [→ 5. (標準) Pascal へのオブジェクト指向拡張](https://qiita.com/ht_deko/items/e23d8c6ae24f0a6c7500) ]

[^1]: "C with Classes" (C++ は当初こう呼ばれていた) のオマージュだと思われます。
[^2]: "Object Pascal Report", Structured Programming (Structured Language World) 9, 3 (1985), pp. 10-15.
[^3]: Delphi 2 以降ではオブジェクト型にもプロパティが使えます。
[^4]: Turbo Pascal 7.0 以降で **private** と **public** が、Delphi では加えて **protected** も使えます。**published** は使えません。
[^5]: "Object Pascal Report", Apple Technical Report No.1 (1985)