Delphi
Borland社によるPascal独自拡張つきの言語とその処理系実装/開発環境な商品。 --戯
- 以前は言語名はObjectPascalと称していたが、最近はDelphi言語と称するようになった。
- Windows用Delphi。姉妹品としてLinux(x86)用Kylix。
OOP拡張
- 単一継承である
- Objectのクラスは全て頂点クラス(TObject)の子孫
- Object変数は必ず参照
- 厳密に言えば、Delphiより古い同社のPascalで使われていた変数埋め込みObjectの形式も(互換性のため)有るが、ほぼ全く使われていないので無視しよう。
- Object変数はクラスと一対一対応の強い型付けがある
- 非Objectなプリミティブ型みたいなのもある
- ここまではJavaとそっくりかな
- 細かい話だが、String型はObjectとは位置付けられておらず、古典的Pascalっぽい扱い
- Interafaceは少なくともVersion1には無かった(T_T)。
- 多重継承「もどき」の機能が一切無いと時々辛い。RTTIで致命的な不可能を回避することも時々可能だが。
- 動的な言語は色々逃げ道があって便利なんだよね(^^;
- メタクラスもどきは有る。
- それ自体はObjectという位置付けではない。自由に書き込める属性とかがあるわけじゃない。単なる正体不明の値でしかない。きっと実体は番号かPointerだろう。
- しかし、それにメッセージを送るような素直な構文で、クラスメソッドを呼ぶことは出来る。
- Class(Objectじゃなく)を代入可能な変数の型は有る。しかも強い型付け。THogeクラスに対応するTHogeClass型を定義できる(自動的には出来ない。欲しくてもまだ無ければ自分で明示的に作ることになる。型の命名規則も無く紳士協定っぽい。左記のように素直に命名するのがお勧め。)
- 強い型付けだから、TAクラスがTBクラスの先祖であるとき、TAClass型変数にTBClass型は代入できるが、逆はコンパイルエラー。
- Classメソッドの多態が(自然なコーディングで)出来る。aClass.aMethod(aaa);と書いたとき、aClassに代入されてるクラスがTAかTBかTCかによって、多態する。
- (普通のInstanceに対する)コンストラクタも(クラスメソッドの一種だから)多態できる。
- つーか、してください。下記のComponentではそうする義務が有ります。それのお陰でDelphi開発環境「知らないClassのInstanceを作る」ことが出来るのですから。
- プロパティという概念がある
- Object(のクラス)の属性またはsetter/getterメソッドのどちらかのエイリアス(?)として、プロパティというものを作れる。
- 普通の属性を読み書きするのと同じ構文で、扱える。
- 実体が属性なのかメソッドなのかはプロパティを使う側からは見えない(気にする必要が無い…はず)なので、そのプロパティが派生属性か否かという実装の詳細を隠蔽できる。
- 本体の属性またはメソッドと、違うアクセス制限(publicとか)を設定できる。本物の属性またはメソッドを隠蔽してプロパティだけ公開とかが出来る。
- setだけ、getだけ、を個別に作れる。だからReadOnlyなプロパティも作成できる。
- getは属性を直接で、setはsetterメソッド経由で、なんてことも可能。
- RTTIてゆーかリフレクションの機能がある
- アクセス制御(public/protected/private)の仲間として第4のアクセス制御「published」が有る。
- publishedなメンバ(特にプロパティで使うと美味しいぞ)は、public公開に加えて、RTTI情報が自動的(?)に作成/公開される。
- そのObjectのユーザーは、そのObjectにどんな名前/型…のメンバが有るかを調べたり、それに基づいて値を読み書きしたり、出来る。
- Delphi開発環境はそれを使ってインスペクタを実現している。
- 当然(?)、ちょっと頑張ればインスペクタ自体を自作できる。開発環境に登録するもよし、独自プログラムの中で活用するもよし。
- ただし変更は出来ない。伝統的な強い型付けのコンパイル言語なもので…
- 普通にコンパイルして普通にアクセスする場合は、RTTIが付いてるプロパティであっても、いちいちRTTIを使っていないようだ。直接アクセスって感じ。両刀使い?
- メソッド参照型
- 例: TMethodWithSenderArg = procedure(Sender: TObject) of object;
- 手続き参照(型)の延長(?)で、メソッドそのものとそのメソッドのレシーバーObjectとの2つの参照を持った構造体みたいな型が有る。
- 型は例によって自作可能。2つの参照という意味ではどれも同じなのだが、シグネチャの違いを表現するために、それぞれの型を作る。 TMethodWithTwoInt = procedure(a, b: integer) of object;
- メソッド参照型の属性やプロパティを作れる。
- Componentのイベントプロシジャは、この仕組みによって成り立っている。
- あるComponentのあるイベントに対応するメソッド参照型プロパティに、イベントプロシジャ参照(と、それを持つObjectの参照)を、保持させる。
- ComponentのコンテナであるForm(窓)のメソッドとして、イベントの応答で行うべき処理を書いちゃう。
- ここが野蛮じゃないか?という意見も有る。Formがイベントプロシジャの100人部屋(笑)になりがちなので。
- 処理のメソッド参照を、Componentの該当プロパティに、代入する。
- もちろんそれを永続化できる。
- 代入(と永続化)は例によって開発環境にお任せ出来る。
名前空間。 Unitと呼ぶ。
- Javaとかと違って階層構造は無い
- これはBorlandのそれ以前のPascalでも存在したんだっけ
メモリ管理
- GCとかは無い(T_T)。基本的にゃCとかと同様の意味で古典的にやるべし。
- String型は自動管理されるが、同じ仕組を他で流用できるわけでもないんで、腹の足しにならない。
- Objectについては、C++みたいな変数埋め込みObjectじゃないし、他になにか仕掛が用意されてるわけでもないので、Scope終了と同時に開放ってのが期待できない。
開発環境がソース自動生成してくれる(しやがる)部分
- ApplicationにFormをぶら下げるという部分は、生成処理のコード全体(といっても数行だが)が自動生成(&必要ならば削除)される。ここはかっこよくない(藁
- FormにWidget(などのComponent)をぶら下げるという部分は、Widgetが代入されるメンバ変数を用意しておく所まで、ソース自動生成される。それしかやらない。
- 実際にインスタンスを生成しPropertyとかを仕込む部分は、ライブラリがやる。ソースにはならない。
- ComponentのNameプロパティには、デフォルト(お任せ)だと、その変数と同じ名がSetされる。
- 名前の自動生成も行われる。たしかそれを支援する(Formの中で衝突しない名を探すための)メソッドが有ったはず…
- イベントプロシジャの宣言や実装(枠だけ)を、要求されたときに生成したり、全く不要だと判ったときに自動削除したり、する。
- Componentのインスペクタのイベントプロシジャ欄をDblClickすると、該当Form(窓)に新規Methodが(お任せな名前、適切なシグネチャで)生成され、そこにソース編集画面のカーソルが飛ぶ。
- 中身が空の(自動生成されたのであろう)Formのイベントプロシジャ用メソッドは、次回のコンパイル時に、自動削除される。
- それを参照してるComponentのプロパティも、自動的にnilクリアされる。
Component、VCL
- TComponentクラスが、Delphi開発環境でのビジュアル開発の要となる(抽象?)クラス。これを駆使して作られた標準添付クラスライブラリがVCL。
- Widgetの類は、TComponent(の子孫であるTControl)の子孫である。
- つまり逆にいえばTControlでないComponentも有るということで、非VisualなComponentも有り。Model的やAction的なものを作るときに。
- 実行時だけじゃなく設計画面でも、「本物の」ComponentのInstanceが生成される。
- Delphiの自慢例(笑):DBアクセスコンポが、設計画面で既にデータ表示できちゃう。
- 裏を返せば、Componentのバグ次第では、設計画面、ひいては開発環境(Delphi)そのものを、簡単に暴走させられる(笑)。Nativeコードだし特に防衛策も施されていない(Processと違って保護(隔離)単位ではない)んで、あっさり破滅します。
- 永続化。
- 上記のPropertyの仕組「だけ」を使ってObjectを保存する。Propertyの値とファイル(などのStream)との間の変換のコードを自作する必要はまず無い。PropertyのRTTIを使ってそれを実行するコードはTComponentに既にあるので、特殊なことをしたい場合でなければ直す必要が無い。
- Object(正確にいえばTComponent)間の参照も、永続化できる。#VBでこれが出来なくて困ったことが有る(^^;てゆーかVBはもとより参照って概念が弱いし。
- Objectの読み出しも同様。上記の多態可能なコンストラクタを使って「Class名だけ」を頼りにInstanceを作ってから、Property値を流し込む。
- メモリ管理もどき
- constructor TComponent.Create(Owner : TComponent);virtual; 子孫クラスもこれを踏襲することになる。
- 「自分の所有者」を決めておくことで、メモリ開放は所有者にお任せする、という素朴(?)なやり方を採用。
- 生成後に所有者を乗り替えることは不可能。ただし最初からnil(親なし)にするのは許されている。
- Visualな窓アプリを作るときは、Application→Form(いわゆる窓)→Widget等という樹形構造で管理する。終了時にはApplicationをDestroyすると全部片付く。
- 永続化の単位は、Form(窓)である。
- Componentだのなんだのの名前の唯一性とかの自動管理は、Formの中で行われる。他のFormには同名のComponentは居るかも知れない。
- Formもクラスなので複数生成可能であることを思うと、1つのForm内で辻褄あわせるのは容易だが、他のFormとの間での参照を安易に管理しようとすると「他のForm」のInstanceが複数生成されたときに「どっちを」参照したら良いのか悩んでしまう。管理を簡単にするためには(ver1の)DelphiがForm内だけを管理することにしたのは、それなりに巧い手だ。
- Form(それ以外のContainer系もだが)はComponentを名前(Nameプロパティ)で検索するメソッドも持つ。
- Component間の参照(ポインタ)もForm内で管理される。
- (同Form内の)他のComponentから参照されてるComponentをデストラクトすると、同Form内の全てのComponentに「今からこのComponentが消えるんで宜しく」という通知(メソッド)が来る。
- 通知を受けたComponentは、自分がそれを参照してたら、参照を忘れる「義務」がある。
- 忘れる処理はComponentの自己責任。
- 自作Componentでは実装忘れに注意。これを忘れると、設計画面でComponentを剥がしたり、Form(やDelphiそのもの)を終了したりしようとする(終了時には当然Componentがデストラクトされるので)と、上記の通りDelphiが暴走する。
- 終了しようとするとハングってことは、前にも後にも進めなくなります(笑)。
このページを編集 (8781 bytes)
|
以下の 11 ページから参照されています。 |
- インスペクタ 最終更新: 2003-12-07, 18:14:16 <airh128>
- オブジェクト指向プログラミング環境 最終更新: 2004-05-30, 17:18:11 <p2077-f>
- プロトタイプベース・オブジェクト指向 最終更新: 2006-04-26, 10:32:39 <khp0591>
- MVC、これでいいのか? 最終更新: 2004-11-10, 11:49:14 <proxy1>
- 自己記述性 最終更新: 2003-07-18, 23:24:54 <flosk5->
- 派生属性 最終更新: 2005-05-19, 19:23:29 <phara>
- オブジェクトの永続化とその方法 最終更新: 2005-08-16, 19:41:37 <phara>
- HyperTalkとプロトタイプベース 最終更新: 2004-12-04, 16:46:06 <adsl-22>
- 仮想関数 最終更新: 2003-10-28, 19:00:20 <61-27-2>
- ソフトウェア配線 最終更新: 2005-01-20, 11:45:54 <61>
- Squeak のとっかかり 最終更新: 2013-02-21, 12:20:35 <phara2>
This page has been visited 16302 times.