皆さんこんにちは 継承についての2つ目の講義では
振る舞いの継承についての続きと
オブジェクトにメッセージをを食った時に 何が起こるかをお教えします。
この一連の講義のゴールは
メッセージ送信のアルゴリズムを 理解することです。
このアルゴリズムによって 送信されたメッセージから
レシーバーに応じてメソッドに 変換することができます。
つまり送られたメッセージに関連して どのメソッドが実行されるのか
そして「self」の意味論 つまり self とは何を意味するのかです。
第1講では
状態についての継承は静的であることを 学びました。
つまりクラスが定義された時に
状態について知ることができます。
しかし振る舞いの継承は動的です。
プログラムが動作している時に
オブジェクトにメッセージを送った時に
クラスやスーパークラスから メソッドを探します。
メッセージ送信は2ステップからなるプロセスです。
まず第1に、メッセージにマッチする メソッドを探します。
第2のステップとして、レシーバー上で メソッドを実行します。
ここに、Rectangle クラスと
ColoredRectangle クラスと
aColoredRectangle という名前の ColoredRectangleのインスタンスがあります。
このオブジェクトに area メッセージを送ります。
探索アルゴリズムは area メッセージに マッチするメソッドを探します。
メソッドを見つけて
aColoredRectangle オブジェクト上で
実行します。
探索アルゴリズムは
オブジェクトにメッセージが送られた時に
実行すべきメソッドを特定します。
明確に2つのステップから成っています。 メッセージ送信とメソッド実行です。
オブジェクトプログラミングでは それらは根本的に異なるものです。
他の言語を使う場合にも
それら2つの区別を理解することは重要です。
aColoredRectangle オブジェクトに area メッセージを送ったら
探索アルゴリズムがまず最初にすることは
レシーバーのクラスを探すことです。
area メッセージのレシーバーは
aColoredRectangle です。
探索アルゴリズムはメソッド探索を
そのオブジェクトのクラス、つまり ColoredRectangle クラスから始めます。
そのクラスの中で area メソッドを探します。
探索アルゴリズムは
そのクラスでは area メソッドを 見つけることはできません。
なので、他の場所を探します。
スーパークラスである Rectangle の中を探します。
そこで area メソッドが見つかります。
そしてそのメソッドを返します。
探索アルゴリズムはメソッドを見つけた時点で 終了します。
2つの場合についてアルゴリズムを 辿ってみましょう。
aColoredRectangle に
color メッセージを送ります。
アルゴリズムはレシーバーのクラスで
color という名前のメソッドを探します。
見つかるので、それを返します。
今度は aColoredRectangle に area メッセージを送ると
アルゴリズムはレシーバーのクラスで the receiver's class
area メソッドを探します。
見つからないので、スーパークラスで探します。
見つかるので、そのメソッドを返します。
self は常にレシーバーを表わしています。
次の例題を見ると
探索アルゴリズムは常にレシーバーを self としていることがわかるでしょう。
クラス A のインスタンスがあります。
メッセージ foo を送ります。
探索アルゴリズムは foo を探します。
見つかって、それを実行します。
B new の場合には B からスタートします。
aB は B new と同じことです。
foo メソッドを探します。
探索アルゴリズムはそれを見つけて
実行して、50 を返します。
なので、10 と
50 が得られます。
時間をかけて self の意味を 考えることが大切です。
2 つの点から説明することが重要です。
「self」 は何を表すのか？
メッセージ送信は
メッセージが self に送られた時 どう振る舞うのか？
「self」と「this」は （this は Java の用語ですが）
同じものです。
それらは常に メッセージのレシーバーを表わしています。
例として
A new foo と B new foo を見ました。
ここで、メッセージ bar を送ってみます。
bar はインスタンスに送られます。
bar はここで見つかって、実行されます。
そして self に メッセージ foo を送ります。
self はこのオブジェクトです。
A new です。
このオブジェクトの メソッド foo を探します。
そのクラスの中でメソッドを探します。
見つかります。実行して、10 を返します。
もう1つの場合も、全く同じです。
しかし、注意してください。 オブジェクトプログラミングの初心者は
よくこれを誤解します。
アルゴリズムは全く同じです。
このオブジェクトに bar を送ります。
bar はここでは見つかりません。
ここで見つかります。 なのでこのbar が実行されます。
この時点で、メッセージ foo が self に送られます。つまり
aB すなわち B new にです。
メッセージ foo を送ると
アルゴリズムがそのオブジェクトのクラスで メソッドを探します。
見つかります。
50 が返されます。
これがアルゴリズムの展開です。
プロセスの各ステップを見てください。 まさに私が今言ったことです。
この例も前の例と
全く同じです。
クラス B は今は空です。
新しいクラス C が定義されて 50 を返すメソッド foo が定義されています。
今やってみせたように アルゴリズムのプロセスを辿ってください。
10 が得られます。
これが最終的に実行される foo です。
ここで 50 が得られます。
まとめると
「self」は Java の「this」と同じように 常にレシーバーを表わします。
メッセージ送信は 常に2つのステップを踏みます。
第1に、探索アルゴリズムは メソッドと、送られたメッセージの
マッチングを探します。
第2のステップは、見つかったメソッドを レシーバーの上で実行することです。
探索アルゴリズムはレシーバーのクラスから 遡って辿っていきます。
探索アルゴリズムのゴールは
レシーバーに送られたメッセージにマッチする メソッドを見つけることです。