ウィキのコピーミラー

これは pascal.chat のウィキのミラーです。編集、履歴、ログインはそちらで行います。

Object Oriented Programming with Free Pascal and Lazarus/ja

English · Español · Français · Italiano · Magyar · Македонски · Русский · 中文(中国) · 中文(台灣) · 日本語

概要

Pascal に関する優れたチュートリアルは数多くあるが、このチュートリアルは初心者をさらに Turbo Pascal,、Delphi、Free Pascal / Lazarusにより提供される標準 Pascalの拡張である、オブジェクト指向プログラミングを深く理解することを目的としている。

オブジェクトは標準パスカルの構造のレコード構造の拡張である。

標準のテキストベースのPascalプログラミングは、1つのことを非常に巧みにこなす伝統的なUnixアプリケーションのようなアプリケーションを作るうえではよいものである。

プログラムが行う「1つのこと」は非常に複雑なアクションであるかもしれないし、ユーザーに複数のメニュー駆動型オプションを提供するかもしれない。しかし、本質的には、ユーザーがキーボードで入力するコマンドに従い、そのレスポンスを端末やプリンターに表示することに制限されている。

グラフィカルユーザーインタフェース (GUI)を提供するために、ある種のオブジェクト指向プログラミングメソッド(C言語やその派生、もしくはVisual Basic、例えばLazarusを用いる、あるいは用いないFree PascalのようなPascalの派生OO)が用いられるのは通常のことである。

GUIでは、ユーザーには以下のような様々な、道具やアクションに紐づけられたウイジェットのセットからなる、整頓された多くの画像が示される。

など。

ユーザーは、画面上でマウスまたはその他のポインター/選択ツールを移動し、マウス ボタンのクリックまたはキーの押下に応じて実行されるアクションを選択することを期待している。

複雑なグラフィカル ユーザー インターフェイスを処理するシステムは、標準の Pascal またはその他のほぼすべてのプログラミング言語で作成できるものの、それぞれのグラフィカルオブジェクトが、画面上で、すべてのプロパティとプロシージャ、共通の構造とともに使用法が結びつけられた関数を持つことのできる、オブジェクト指向システムを用いるほうがはるかにたやすい。

オブジェクト - 現実世界の相似

病院や診療所で採取された血液サンプルの例を考えてみよう。

血液サンプル

物理的なサンプルは文字通り「実体」- objectであり、情報、ドキュメント、他の多くの物理的なオブジェクトが紐づけられている。

患者のカルテには、医師がしかるべき時に期待する結果を確認させる、要望文書のコピーが加えられる。

実際の 結果 が医師の診断を助けるために記録され、患者のカルテに検査結果のコピーが挟まれる。

物理的なサンプルは参照、確認、あるいはさらなる検査のために保存されるか、流しに捨てられる、あるいは焼却処分される。これを述べた方法があるだろう。

医師はサンプルが採取されるたびに、いちいちすべての細目と指示を書き込む必要はなく、検査室でそのサンプルがどのように検査されるかほとんど知らないだろう。この様々な課程の細目は、以前のサンプル採取と分析から継承され、全体の結果に対する、一定の計画、血液サンプルに対して考えらえる、ドキュメントとデータ、その基礎のメソッドを複合がオブジェクトである。 医師の考えでは、血液サンプルはその結果とほぼ同じ実体とみなされ、看護師や技師にとっては、サンプル、チューブ、ラベル、および保管状態が再び単一の実体を成す。

別の例 - 自動車

もし、血を見るのが嫌ならば、同様の理屈が車庫から、修理場へ運ばれる自動車にも適用できる。 それは以下よりなっているだろう:

プログラミング例

こんな実社会の事例に没頭するのはもうたくさんだ! 主題のObject Pascalでのプログラミングに進もう。

Free Pascal/Lazarusでいくつかのコントロールを持つ簡単なフォームを作ることを考える。

Lazarus IDEを起動すると、プログラマにはフォーム設計の様々なコントロールや、オブジェクトを置くことを促す、空のテンプレートがもたらされる。

あらかじめ作られたフォームがすでにオブジェクトであるとこに注意すること。それは位置(上辺、左)、大きさ(高さ、幅)、色、テキストを加えるときのデフォルトのフォントなどのプロパティを持つ。


もしボタンコントロール(TButton型)がフォームに置かれると、それは、オブジェクトインスペクタで検討できるそれ自身の一連のプロパティを持つ。

そのプロパティのいくつかはフォームと似たような名前を持っている。これはある共通のその派生クラスによって、どのようにそのプロパティが定義され、扱われるかをレイアウトする祖先クラスから継承されたプロパティであることが理由である。

プロパティ同様に、オブジェクトインスペクタはアプリケーションがどのように、例えばマウスボタンクリック(OnClick)もしくは位置や、大きさ、他のプロパティを変更(OnChange)したときに、それらを扱うかを指示するメソッドであるイベントハンドラにアクセスするイベント(Events)という名前のタブを持つ。

フォーム上の物理的な画像であるボタンは、そのプロパティとイベントハンドラと相まって、パスカルでは単一の実体オブジェクト(Object)とみなされる。

標準パスカルに対するオブジェクト指向拡張

Pascalのレコード構造はオブジェクトを定義することで拡張された。

オブジェクト

オブジェクトは特別な種類のレコードである。 レコードには、次のすべてのフィールドが含まれる。 (従来のレコードと同様に) オブジェクトの定義で宣言されるが、プロシージャと関数はレコードの一部であるかのように宣言でき、オブジェクトの型に関連付けられたメソッドへのポインタとして保持されるようになった。

例えば、平均を計算するメソッドともに実数値の配列を保持するオブジェクトを仮定する。

pascal
Type
  Average = Object
    NumVal: Integer;
    Values: Array [1..200] of Real;
    Function Mean: Real; { 配列の平均値を計算する }
  End;

「オブジェクト」はフィールドとメソッドを「親」オブジェクトから「継承」することができる。これはこれらのフィールとメソッドが、「子」として宣言されたオブジェクトに含まれているかのように、用いることができることを意味する。

さらに、視認性の観念は、フィールド、プロシージャ、関数がpublic、protected、privateとして宣言することを可能とした。デフォルトではフィールドとメソッドはpublicで、現在のユニットの外側へエクスポートできる。Protectされたフィールドやメソッドは現在の祖先オブジェクトから派生したオブジェクトにとってのみ利用可能である。Privateで宣言されたフィールドや、メソッドは現在のユニットでのみアクセスが可能である:そのスコープは現在のユニットの実装に限られている。

クラス

オブジェクトはFree PascalとLazarusではそう頻繁には用いられない。むしろ、クラス(Class)は広く用いられる。クラスはほとんどオブジェクトと同様に宣言されるが、オブジェクト自身というよりはオブジェクトに対するポインタである。技術的には、これはプログラムのヒープに割り当てられるが、オブジェクトはスタックに割り当てられる。

これはクラス宣言の典型的な例である:

pascal
{-------------------------------------------}
{        LCLからのクラス宣言の例            }
{-------------------------------------------}
  TPen = class(TFPCustomPen)
  private
    FColor: TColor;
    FPenHandleCached: boolean;
    FReference: TWSPenReference;
    procedure FreeReference;
    function GetHandle: HPEN;
    function GetReference: TWSPenReference;
    procedure ReferenceNeeded;
    procedure SetHandle(const Value: HPEN);
  protected
    procedure DoAllocateResources; override;
    procedure DoDeAllocateResources; override;
    procedure DoCopyProps(From: TFPCanvasHelper); override;
    procedure SetColor
         (const NewColor: TColor; const NewFPColor: TFPColor); virtual;
    procedure SetFPColor(const AValue: TFPColor); override;
    procedure SetColor(Value: TColor);
    procedure SetMode(Value: TPenMode); override;
    procedure SetStyle(Value: TPenStyle); override;
    procedure SetWidth(value: Integer); override;
  public
    constructor Create; override;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    property Handle: HPEN read GetHandle write SetHandle; deprecated;
    property Reference: TWSPenReference read GetReference;
  published
    property Color: TColor read FColor write SetColor default clBlack;
    property Mode default pmCopy;
    property Style default psSolid;
    property Width default 1;
  end;

このクラスは他のparent(親)もしくはancestor(祖先)クラス(TFPCustomPen)のインスタンスとして宣言されていることに注意すること。その祖先から、すべてのプロパティとメソッドをinherit(継承)している。このクラスはそれ自身のフィールドを有しており、以下にグループ化されている。

メソッド

メソッドは標準のプロシージャ、もしくは関数に似ているが、いくつかの指令(directive)を持つ。 上記で定義されているメソッドのいくつかは指令、virtual、他はoverride指令が付けられている。

Virtualあるいはoverride指令のないメソッドは静的(static)メソッド(Pascalにおける通常の種類)である。Virtualあるいはoverride指令は動的(dynamic)である。

メソッドの特定のインスタンスは:

プロパティ

プロパティは従来的なPascalにおける通常のフィールドに似ているが、読み取り(read)あるいは/および書き込み(write)指示子を持つ。

例

pascal
  TFooClass = class
  private
    FIntProp: Integer;
  public
    property IntProp: Integer read FIntProp write FIntProp;
  end;
pascal
  TFooClass = class  
  private
    function GetListProp(AIndex: Integer): String;
    procedure SetListProp(AIndex: Integer; AValue: String);
  public
    // プロパティのこの型はクラスのpublishedセクションにはないだろう
    property ListProp[AIndex: Integer]: String read GetListProp write SetListProp; 
  end;
pascal
  TFooClass = class
  private
   function GetValue(const AIndex: Integer): Integer;
   procedure SetValue(const AIndex: Integer; AValue: Integer);
  public
    // note that the read and write methods are shared
    property Value1: Integer index 1 read GetValue write SetValue;
    property Value2: Integer index 2 read GetValue write SetValue;
    property Value3: Integer index 3 read GetValue write SetValue;
    property Value4: Integer index 4 read GetValue write SetValue;
    // インデクスは定数か、数値、あるいは型を列挙することもできる
    // 例えば:
    // property Value: Integer index ord(seSomeEnum) read SomeFunction write SomeProcedure;
  end;

Free Pascal 言語拡張

FPCはオブジェクト指向プログラミングをサポートするためにその「標準」Pascal文法にいくつかの言語拡張を含んでいる。

これらの拡張はFPC Language Reference Guide http://www.freepascal.org/docs.var.(訳注: このリンクは無効であるFPCのリファレンスに対するURLは https://www.freepascal.org/docs-html/current/ref/ref.html である)で述べられており、それぞれの概念に対するチュートリアルへのリンクもある。Language Reference Guideはこの概要チュートリアルには含まれない文法便覧とさらなる細部を含んでいる。上記には4つの言語仕様が含まれており、ObjectsとClassesはFPCとLazarusにおける、オブジェクト指向プログラミング (OOP)の基礎を成している。OOP初心者にとって、Objectsセクションはより概説的なセクションで、ClassesセクションはObjects文法に対する類似性と相違性を強調することで、反復を最小限にしている。一般的に Classes 実装はDelphi、Lazarus開発者により広く用いられている。FPCではOOPの Classes 方言で、何が実際「class」なのかに言及することに「object」がよく使われている。これらのドキュメントは命名上の混乱を最小限にするために記述されているが、このドキュメント以外では、通常、 Class から作られるオブジェクトに用語「object」が用いられている。実際、FPCランタイムライブラリ(RTL)は TObject と呼ばれる基底 class を持つクラスライブラリを含んでいる。

古いTurbo Pascal OOP実装に慣れているユーザーはオブジェクト実装が古いTurbo Pascal方言に基づいているため、Classesセクションを初めは飛ばしたいかもしれない。ClassesセクションはDelphi文法に基づいているため、Delphiユーザーにはなじみがあるはずだ。Classesセクションの書き方はObjectsセクションからの概念を参照しているかもしれないことに注意すること。様々なApple、THINK、MPW Object Pascal方言になじみのあるマッキントッシュ開発者にとって、FPC ObjectsもしくはClasses方言のいずれも直接的な移行パスとならないだろう。2009年 3月時点では、Mac PascalメーリングリストではAppleのObjective C / Cocoa フレームワークにアクセスするためにあるコンパイラサポート(新しい文法)を提供する可能性が議論されている。

オブジェクト指向 Pascal 一般的な概念

OOPは利用可能な他の言語仕様と設計に比べ、データの取り扱いとカプセル化とプログラムフローを取り扱う異なる方法を提供する。OOP は多くの場合、グラフィック ユーザー インターフェイス (GUI) や物理システムなどの特定のアプリケーションを、より自然な感覚でモデル化するのに役立つ。しかし、OOPはすべてのアプリケーションに適切ではない。プログラムコントロールはより基本的なPascal手続き的構造ほど明示的ではない。OOPから最も恩恵を受けるためには、学習曲線が急であることを通常必要とする、大きなクラスライブラリの理解が必須とされる。厳格な手続き的コードをメンテナンスすることに比べ、大規模なOOPアプリケーションコードをメンテナンスすることは、その利点と、欠点がある。OO分析、設計とプログラミング技法に対する豊富な学習教材があるが、それらは本稿の範疇を超えてしまう。

拡張、あるいはその言語の基本として、OOPフィーチャを取り込んだ多くのプログラミング言語が存在する。このように、OOコンセプトを記述するために多くの異なる用語がある。FPCですら、いくつかの命名上の重複がある。一般的に、OOPはデータ上で機能するデータとプロシージャの関連したセットを明示的に組み合わせ、カプセル化するプログラミングオブジェクト(もしくは、情報ユニット)の概念よりなっている。データは通常、プログラムの実行中に永続的だが、グローバル変数の宣言に固有の問題を軽減するメカニズムが備わっている。さらに、OOP 言語を使用すると、以前に定義されたオブジェクトに基づいてオブジェクトを段階的に変更および/または拡張できる。 この機能は通常、継承およびポリモーフィズムという用語で呼ばれる。多くのOOP言語は、1つのオブジェクトに属する、プロシージャを称するのに、メソッド もしくは メッセージ用語を用いる。OOPの力の源泉はコンパイルバインディングよりも、メソッドの遅い(実行時)、動的なバインディングによって、認識される。このメソッドの動的なバインディングは、プロシージャ変数とプロシージャ パラメータの使用に似ているが、構文の凝集性が高く、関連するデータとのカプセル化が行われ、以前に定義されたメソッドの動作も継承される。次の Wiki ページは、オブジェクト指向の方法での分析、設計、プログラミングについてさらに詳しく知るための出発点を提供する。

さらなる情報

これは、この話題についてほんの触りを述べたに過ぎない。より詳細には、Free Pascalマニュアルの特に、5章(Objects)と6章(Classes)を読むことを強く推奨する。

ボーランドはまた、寛大にもPDF媒体で、オリジナルのTurbo Pascalマニュアルから、オブジェクト指向プログラミングの章を解放していた。この章ではこの言語仕様をボーランドがTurbo Pascalに導入したときからが書かれている。これは古いかもしれないが、OOPの理論は今日でも非常に関連性がある。Linkの「その他」のカテゴリから、ダウンロードできる。

以下も参照のこと

外部リンク


From the Free Pascal wiki, page "Object Oriented Programming with Free Pascal and Lazarus/ja", as it stood on 2024-04-03 after a change by Ariben, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.

第2版、最終更新:WikiArchive 。