inherited は、「上位クラスから継承したメソッドの呼び出し」ということをまず頭に入れておいて下さい。早速例を見てみましょう。
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) ListBox1: TListBox; Button1: TButton; procedure Button1Click(Sender: TObject); private { Private 宣言 } public { Public 宣言 } end; TBase = class(TObject) public procedure ShowName; end; TDerived = class(TBase) // TBase から派生 public procedure ShowName; end; var Form1: TForm1; implementation {$R *.dfm} { TBase } procedure TBase.ShowName; begin Form1.ListBox1.Items.Add('Base'); end; { TDerived } procedure TDerived.ShowName; begin inherited; // 上位クラスのメソッドの呼び出し。 Form1.ListBox1.Items.Add('Derived'); end; procedure TForm1.Button1Click(Sender: TObject); var Derived: TDerived; begin Derived := TDerived.Create; (* ブレークポイント *) Derived.ShowName; Derived.Free; end; end.
結果は、以下のようになります。
上記のプログラムの中で、「(* ブレークポイント *)」とコメントしてある場所にブレークポイントを設置して F7 キーを押していってみてください。コードの実行手順を見る事が出来ます。
inherited についてですが、冒頭でも述べてあるように上位クラスから継承したメソッドの呼び出しを行っています。まず初めに、Button1 をクリックして実行されるコードから見ていきます。
procedure TForm1.Button1Click(Sender: TObject); var Derived: TDerived; begin Derived := TDerived.Create; Derived.ShowName; Derived.Free; end;
まず、TDerived 型の変数 Derived を宣言しています。次に、TDerived クラスのオブジェクトを生成し、それを Derived 変数に代入しています。(厳密に言うと、クラス型の変数はポインタです。ここでは単に、クラス型の変数はポインタと言う事だけ、覚えておいて下さい。)
Derived 変数は、TDerived 型のオブジェクトを参照しているので、Derived.ShowName では、TDerived 型で定義してあるメソッドが呼ばれることになります。つまり以下のコードが呼ばれることになります。
procedure TDerived.ShowName; begin inherited; Form1.ListBox1.Items.Add('Derived'); end;
ここで、inherited; が宣言されています。まず結論から述べますと、この inherited; は、TBase.ShowName; を呼び出します。
図にしますと、以下のような感じになります。
文字色を「青」にしたところに注目してください。inherited; が記述されている所で実行されるコードは、それが記述されているメソッド名(ここでは、ShowName )と同じ識別子が上位クラスにあれば、その上位クラスのメソッドが呼び出されます。ここでは、TDerived の上位クラスの TBase クラスに、記述中の手続きと同じ名前のメソッド( ShowName )があります。ですから、TBase.ShowName が呼び出されることになります。
もし、同名のメソッド名が上位クラスに無ければ、Delphi は、inherited を無視します。以下の例を見てください。
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) ListBox1: TListBox; Button1: TButton; procedure Button1Click(Sender: TObject); private { Private 宣言 } public { Public 宣言 } end; TBase = class(TObject) public procedure ShowName; end; TDerived = class(TBase) public procedure ShowName2; // 若干、名前が変わりました。 end; var Form1: TForm1; implementation {$R *.dfm} { TBase } procedure TBase.ShowName; begin Form1.ListBox1.Items.Add('Base'); end; { TDerived } procedure TDerived.ShowName2; begin inherited; // この inherited は、無視されます。 Form1.ListBox1.Items.Add('Derived'); end; procedure TForm1.Button1Click(Sender: TObject); var Derived: TDerived; begin Derived := TDerived.Create; Derived.ShowName2; Derived.Free; end; end.
結果は以下のようになります。
TDerived.ShowName2 メソッドの中で、inherited を使用していますが、この TDerived クラスの上位クラスには、ShowName2 という名前をもつメソッドはありません。ですから、この場合の inherited は無視される事になります。
それでは、メソッドがパラメータ(引数)を持つ場合に、inherited を使用するとどうなるのでしょうか。以下の例を見てください。
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; ListBox1: TListBox; procedure Button1Click(Sender: TObject); private { Private 宣言 } public { Public 宣言 } end; TBase = class(TObject) public procedure ShowName(name: string); // 引数を持ちます。 end; TDerived = class(TBase) public procedure ShowName(name: string); // 引数を持ちます。 end; var Form1: TForm1; implementation {$R *.dfm} { TBase } procedure TBase.ShowName(name: string); begin Form1.ListBox1.Items.Add('Base'+name); end; { TDerived } procedure TDerived.ShowName(name: string); begin inherited; // メソッド呼び出しで、引数はどうなる? Form1.ListBox1.Items.Add('Derived'+name); end; procedure TForm1.Button1Click(Sender:TObject); var Derived: TDerived; begin Derived := TDerived.Create; Derived.ShowName('--Hello!--'); Derived.Free; end; end.
結果は以下のようになります。
結果を見てみますと、上位クラスのメソッドが呼び出されるとき、つまり TBase.ShowName(name: string) が呼び出されるとき、呼び出し元に与えられたパラメータが渡されている事が分かります。
inherited の後ろに引数を伴う場合でも、基本的なことは変わりません。冒頭でも述べたとおり上位クラスから継承したメソッドの呼び出しが inherited の役目です。引数には、どのメソッドを呼び出すかを指定してやる事になります。早速例を見てみましょう。
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; ListBox1: TListBox; procedure Button1Click(Sender: TObject); private { Private 宣言 } public { Public 宣言 } end; TBase = class(TObject) public procedure ShowName; end; TDerived = class(TBase) public procedure ShowName; end; var Form1: TForm1; implementation {$R *.dfm} { TBase } procedure TBase.ShowName; begin Form1.ListBox1.Items.Add('Base'); end; { TDerived } procedure TDerived.ShowName; begin inherited ShowName; // 引数を指定しています。 Form1.ListBox1.Items.Add('Derived'); end; procedure TForm1.Button1Click(Sender:TObject); var Derived: TDerived; begin Derived := TDerived.Create; Derived.ShowName; Derived.Free; end; end.
結果は、以下のようになります。
この場合は、一番最初の例と全く同じになります。inherited の後ろに引数を指定すると、上位クラスのどのメソッドを呼び出すのかを指定しているだけです。ここでは、記述中のメソッド( TDerived.ShowName ) と、呼び出そうとするメソッド名が同じなので、inherited の後ろの引数を省略した場合と全く同じになります。
引数を指定する場合には、上位クラスのどのメソッドを呼び出すかを指定できますので、以下のようなことができるようになります。
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; ListBox1: TListBox; procedure Button1Click(Sender: TObject); private { Private 宣言 } public { Public 宣言 } end; TBase = class(TObject) public procedure ShowName; procedure ShowClass; end; TDerived = class(TBase) public procedure ShowName; end; var Form1: TForm1; implementation {$R *.dfm} { TBase } procedure TBase.ShowClass; begin Form1.ListBox1.Items.Add('Base-ShowClass') end; procedure TBase.ShowName; begin Form1.ListBox1.Items.Add('Base-ShowName'); end; { TDerived } procedure TDerived.ShowName; begin inherited ShowClass; // 引数を指定しています。 Form1.ListBox1.Items.Add('Derived-ShowName'); end; procedure TForm1.Button1Click(Sender:TObject); var Derived: TDerived; begin Derived := TDerived.Create; Derived.ShowName; Derived.Free; end; end.
結果は、以下のようになります。
inherited の後ろの引数に注目してください。このように上位クラスのどのメソッドを呼び出すかを指定しています。
inheited の後ろで指定するメソッドがパラメータを持つ場合の例です。
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; ListBox1: TListBox; procedure Button1Click(Sender: TObject); private { Private 宣言 } public { Public 宣言 } end; TBase = class(TObject) public procedure ShowName(name: string); procedure ShowNumber(int: Integer); end; TDerived = class(TBase) public procedure SimpleMethod1; procedure SimpleMethod2; end; var Form1: TForm1; implementation {$R *.dfm} { TBase } procedure TBase.ShowName(name: string); begin Form1.ListBox1.Items.Add('Base '+name); end; procedure TBase.ShowNumber(int: Integer); begin Form1.ListBox1.Items.Add('Base '+IntToStr(int)); end; { TDerived } procedure TDerived.SimpleMethod1; begin inherited ShowName('Test'); Form1.ListBox1.Items.Add('TDerived.SimpleMethod1'); end; procedure TDerived.SimpleMethod2; begin inherited ShowNumber(2002); Form1.ListBox1.Items.Add('TDerived.SimpleMethod2') end; procedure TForm1.Button1Click(Sender:TObject); var Derived: TDerived; begin Derived := TDerived.Create; Derived.SimpleMethod1; ListBox1.Items.Add('========'); Derived.SimpleMethod2; Derived.Free; end; end.
結果は、以下のようになります。
inherited の後ろでメソッドを指定するときに引数を指定してやる事で、上位クラスのメソッド呼び出し時に、その指定した引数を渡す事になります。
メソッド内で inherited を記述する位置を変更することで、実行順序を変える事ができます。つまり、上位クラスのメソッドを最初に実行するのか、或いは、最後に実行するのか等を調整することができます。
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; ListBox1: TListBox; procedure Button1Click(Sender: TObject); private { Private 宣言 } public { Public 宣言 } end; TBase = class(TObject) public procedure ShowName; end; TDerived1 = class(TBase) public procedure ShowName; end; TDerived2 = class(TBase) public procedure ShowName; end; var Form1: TForm1; implementation {$R *.dfm} { TBase } procedure TBase.ShowName; begin Form1.ListBox1.Items.Add('Base'); end; { TDerived1 } procedure TDerived1.ShowName; begin inherited; Form1.ListBox1.Items.Add('Derived1'); end; { TDerived2 } procedure TDerived2.ShowName; begin Form1.ListBox1.Items.Add('Derived2'); inherited; end; procedure TForm1.Button1Click(Sender: TObject); var Derived1: TDerived1; Derived2: TDerived2; begin Derived1 := TDerived1.Create; Derived1.ShowName; Derived1.Free; ListBox1.Items.Add('========'); Derived2 := TDerived2.Create; Derived2.ShowName; Derived2.Free; end; end.
結果は、以下のようになります。
このように、inherited の位置により実行順序を変える事が可能です。
メッセージハンドラ内の inherited でメソッド名が指定されていない場合、同じメッセージ番号を持つ上位クラスのメッセージハンドラが呼び出されます。同じメッセージ番号をもつメッセージハンドラが上位クラスにない場合、Delphi は DefaultHander を呼び出します。また、メッセージハンドラのメソッド名は、必ずしも上位クラスのメソッド名と同じでなくても構いません。