Object Oriented Programming with Free Pascal and Lazarus/ja

From Free Pascal wiki
Jump to navigationJump to search

English (en) español (es) français (fr) magyar (hu) italiano (it) 日本語 (ja) македонски (mk) русский (ru) 中文(中国大陆)‎ (zh_CN) 中文(台灣)‎ (zh_TW)

概要

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

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

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

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

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

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

  • メニューから選択する
  • ファイルを開く、保存する
  • インターネットに接続する
  • 算術演算を行う

など。

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

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

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

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

血液サンプル

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

  • サンプルの入った試験管、の型は医師が望む試験の種類を規定する
  • ローカルルール (または メソッド, スタンダードオペレーティングプロシージャ) は看護師や技師にサンプルを集める指示を出す
    • どの種類の試験管が用いられるべきか
    • サンプルがどのように扱われるべきか
    • 検査室に運ばれるまでどのように保存されるべきか
  • ラベルは以下の細目について記載されている
    • サンプルの識別記号番号
    • 患者の氏名と誕生日
    • 採取した日付と時刻
    • 必要とする検査
  • 要望文書 それはサンプルとともに検査室へもたらされ、指示には
    • サンプルの識別記号番号
    • 指示した医師のID
    • 医師が望んだ検査
    • 患者のより詳しい情報
    • 確認が求められている、可能性がある診断

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

  • 検査室では - ローカルメソッドが以下を規定する
    • どのようにサンプルが分析されるか
    • どの機器を用いるか
    • どのようにその機器が補正され、運転されるべきか
    • どのように結果が保存され、形式が整えられるか
    • 医師に結果を報告すること

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

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

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

別の例 - 自動車

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

  • 自動車自身
  • 所有者によって保存されている、登録証、車両ナンバー(車両ナンバープレートを含む)、保険証、購入の領収書、部品、修理などの書類
  • 燃料消費履歴
  • その自動車を使うことのできる運転者、およびその免許書
  • 修理場でのサービス記録
  • 定期点検とメンテナンスの方法(メソッド)と手順(プロシージャ)を追う書類
  • 非定期点検、修理を追うメソッド
  • 顧客の支払い情報

プログラミング例

Enough of this pre-occupation with Real-World examples! Let us proceed to the main purpose: programming in Object Pascal.

Let us consider the creation of a simple Form with a few controls for an application in Free Pascal/Lazarus.

ObjectInspector-TForm.png
BlankForm.png

On invoking the Lazarus IDE, the programmer is presented with a blank template Form design, on which he is encouraged to place various controls or objects.

Note that the pre-made blank Form is already an Object, with its own properties such as position (Top and Left), size (Height and Width), colour, default font for adding text etc.



If a Button control is placed on the Form (type TButton), it will have its own series of properties, which can be examined in the Object Inspector window.

Several of the properties have names similar to those for the Form; this is because many properties are Inherited from some common Ancestor class, which lays out how properties are to be defined and handled by the descendant classes.

As well as properties, the Object Inspector offers a tab called Events, which gives access to Event Handlers which are methods instructing the application how to deal with things such as a mouse click on a button (OnClick) or some change in the position, size or other properties (OnChange).

The physical image of the Button on the Form, together with all its properties and Event Handler methods, should be regarded as a single entity or Object in Pascal.

ObjectInspector-TButton.png
FormWithButton.png
Source FormWithButton1.png

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

The Pascal record structure is extended by defining an

オブジェクト

An Object is a special kind of record. The record contains all the fields that are declared in the object's definition (just like a conventional record), but now procedures and functions can be declared as if they were part of the record and are held as pointers to the methods associated with the object's type.

For example, an object could contain an array of real values, together with a Method for calculating the average.

Type
  Average = Object
    NumVal: Integer;
    Values: Array [1..200] of Real;
    Function Mean: Real; { calculates the average value of the array }
  End;

Objects can ”inherit” fields and methods from ”parent” objects. This means that these fields and methods can be used as if they were included in the objects declared as a ”child” object.

Furthermore, a concept of visibility is introduced: fields, procedures and functions can be declared as public, protected or private. By default, fields and methods are public, and can be exported outside the current unit. Protected fields or methods are available only to objects descended from the current ancestor object. Fields or methods that are declared private are only accessible in the current unit: their scope is limited to the implementation of the current unit.

クラス

Objects are not used very often by themselves in Free Pascal and Lazarus; instead, Classes are used very widely. A Class is defined in almost the same way as an Object, but is a pointer to an Object rather than the Object itself. Technically, this means that the Class is allocated on the Heap of a program, whereas the Object is allocated on the Stack.

Here is a simple example of a typical Class declaration:

{-------------------------------------------}
{ Example of Class declaration from the 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;


Note that this class is defined as an instance of another parent or ancestor class (TFPCustomPen) from which it inherits all its properties and methods. It has some fields of its own, grouped under

  • private - this means that items defined here are only available or visible to other classes or procedures/function defined within the same program unit (this example is from Graphics, so any of the other classes such as TBitMap, TPicture etc in the same unit can use them). They are essentially local variables (eg FColor, FPenHandleCached) or locally used methods (GetHandle, SetHandle) but can be used or referred to in items declared in the protected or public sections.
  • protected - this means that items defined here are only available or visible to classes that are descended from this ancestor class, and inherit its properties or methods
  • public - this means that items defined here are available to any programming unit that includes the current unit in its Uses clause
  • published - is the same as a public section, but the compiler also generates type information that is needed for automatic streaming of these classes. Often the list of published items appear in the Object Inspector of Lazarus; if there is no published list, all the public fields usually appear in the Object Inspector.

メソッド

A method is just like a standard procedure or function, but can have some additional directives.

Some of the methods defined above are labelled with the directive virtual; others are labelled with the override directive.

  • virtual means that the type or actual instance of a method is not known at compile-time, but is selected at run-time depending on what sub-program actually calls the method. It could be considered a place-holder in the definition of the class.
  • override means that at run-time the locally given definition can take the place of a definition inherited from an ancestor class, particularly if it was virtual. If you particularly want to use the method defined in the ancestor class, it is sometimes necessary to call it specifically with the inherited clause.

Methods with no virtual or override directive are static methods (the usual kind in Pascal). Those with a virtual or override directive are dynamic.

Special instances of methods are:

  • create - a constructor for a class, which takes care of allocating memory, collecting together all the information needed and configuring/initializing the various properties.
  • destroy - a destructor for a class, which removes all the parts of the class from the system in an orderly and logical way, and returns all its resources for the system to re-use.

プロパティ

Properties are just like ordinary fields in a conventional Pascal record, but they can have read and/or write specifiers.

  • read specifier is a field, or a function that returns a result of the correct type for the property. In the example above, the property Color has a read specifier FColor, which is a local variable containing the value to be used. If a property has a read but no write specifier, it is read-only.
  • write specifier is a field, or a procedure that will store the value of the property in a specific location. In the example above, Color has a write specifier SetColor that is a procedure (defined in the protected section) for writing the color value to some specified location. If a property has a write but no read specifier, it is write-only.
  • default - note that it is possible to set a default value for a property. For example, Color here is given the default value clBlack, or black, at the time of creation. It could subsequently be given a different value, by a programming assignment statement, or in the Object Inspector.
  • index specifier is an integer that the read or write methods, shared between properties, can use to identify which property is desired. Note that if index is used the read or write specifiers must be a function or a procedure respectively and cannot be a normal field/variable.

  TFooClass = class
  private
    FIntProp: Integer;
  public
    property IntProp: Integer read FIntProp write FIntProp;
  end;
  TFooClass = class  
  private
    function GetListProp(AIndex: Integer): String;
    procedure SetListProp(AIndex: Integer; AValue: String);
  public
    // this type of property may not be in the published section of a class
    property ListProp[AIndex: Integer]: String read GetListProp write SetListProp; 
  end;
  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;
    // index may be a const or a number or you can even use an enumerated type
    // for example:
    // property Value: Integer index ord(seSomeEnum) read SomeFunction write SomeProcedure;
  end;

Free Pascal 言語拡張

FPC includes several language extensions to its "standard" Pascal syntax to support object oriented programming.

These extensions are described in the indicated chapters of the FPC Language Reference Guide: http://www.freepascal.org/docs.var. Links to tutorial pages for each concept are included above as well. The Language Reference Guide includes syntax diagrams and further details not contained in this introductory tutorial. Of the four language features listed above, Objects and Classes form the basis of object oriented programming (OOP) in FPC and Lazarus. For those new to OOP, the Objects section includes more introductory concepts and the Classes section minimizes repetition by emphasizing the similarities and differences to the Objects syntax. In general, the Classes implementation seems to be more widely in use including Delphi Lazarus developers. Often the word "objects" is used to refer to what is actually a "class" in the Classes dialect of OOP in FPC. These documents will be worded to minimize any terminology confusion, but outside of this document, the term "object" oftentimes refers to objects created from a Class. In fact, the FPC run time library (RTL) includes a class library with a base class called TObject.

Users familiar with the older Turbo Pascal OOP implementation may initially want to skip the section on Classes since the Objects implementation is based on the older Turbo Pascal dialect. The section on Classes should be familiar to Delphi users since it is based on Delphi syntax. Be aware that some of the writeup in the Classes section may refer to concepts from the Objects section. For Macintosh developers familiar with the various Apple, THINK and MPW Object Pascal dialects, neither the FPC Objects or Classes dialects provide a direct migration path. As of March 2009, there are discussions on the Mac Pascal Mailing list about potentially providing some compiler support (new syntax) for accessing Apple's Objective C / Cocoa framework.

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

OOP provides different ways to manage and encapsulate data and to manage program flow compared with other available programming language features and constructs. OOP often lends itself to modeling certain applications such as Graphic User Interfaces (GUI's) and physical systems in a more natural feeling manner. However OOP is not appropriate for all applications. Program control is not as explicit as the more basic Pascal procedural constructs. To obtain the most benefit from OOP, understanding of large class libraries is often required which can entail a steep learning curve. Maintaining large OOP application code has its advantages and disadvantages compared to maintaining strictly procedural code. There are many sources for learning OO analysis, design and programming techniques which are beyond the scope of this guide.

There are numerous programming languages which incorporate OOP features as extensions or the basis of their language. As such, there are many different terms for describing OO concepts. Even within FPC, some of the terminology overlaps. In general, OOP usually consists of the concept of a programming object (or information unit) which explicitly combines and encapsulates a related set of data and procedures which act on the data. This data is usually persistent during program execution but with mechanisms to reduce some of the problems inherent in declaring global variables. In addition, OOP languages enable objects to be incrementally modified and/or extended based on previously defined objects. This feature is usually referred to by the terms inheritance and polymorphism. Many OOP languages use the terms method or message referring to procedures which belong to an object. Much of the power of OOP is realized by late (run time) dynamic binding of methods rather than compile binding. This dynamic binding of methods is similar to using procedural variables and procedural parameters but with greater syntactic cohesion, encapsulation with the data it is related to and also inheritance of behavior of previously defined methods. The following wiki pages provide a starting point for discovering more about analysis, design and programming in an object orient manner.

さらなる情報

This has only scratched the surface of the topic. For more details, readers are strongly recommended to read the Free Pascal manuals, especially Chapters 5 (Objects) and 6 (Classes)

Borland was also kind enough to release the Object Oriented Programming chapter from the original Turbo Pascal manuals in PDF form. This chapter is from when Borland introduced this new language feature into Turbo Pascal. The chapter might be old, but the OOP theory is still very relevant today. You can download a copy from the following link under the "Other" category.

以下も参照のこと

外部リンク