Out of Memory

本ブログは更新を停止しました。Aerieをよろしくお願いいたします。

目次

Blog 利用状況

ニュース

2009年3月31日
更新を停止しました。引き続きAerieを御愛顧くださいませ。
2009年2月3日
原則としてコメント受付を停止しました。コメントはAerieまでお願いいたします。
詳細は2月3日のエントリをご覧ください。
2008年7月1日
Microsoft MVP for Developer Tools - Visual C++ を再受賞しました。
2008年2月某日
MVPアワードがVisual C++に変更になりました。
2007年10月23日
blogタイトルを変更しました。
2007年7月1日
Microsoft MVP for Windows - SDKを受賞しました!
2007年6月20日
スキル「ニュース欄ハック」を覚えた!
2006年12月14日
記念すべき初エントリ
2006年12月3日
わんくま同盟に加盟しました。

カレンダー

中の人

αετο? / aetos / あえとす

シャノン? 誰それ。

顔写真

埼玉を馬鹿にする奴は俺が許さん。

基本的に知ったかぶり。興味を持った技術に手を出して、ちょっと齧りはするものの、それを応用して何か形にするまでは及ばずに飽きて放り出す人。

書庫

日記カテゴリ

【思考実験】ポリモーフィズム

#書きたい記事はいっぱいあるんだけど、重いやつは後回し…w

オブジェクト指向の三本柱は「カプセル化」「継承」「多態性」だと言われる。
最近、この「多態性」ってやつがよくわからなくなってきた。

一般的な説明は、「同じメソッドでもクラスが違えば挙動が違う」というやつだ。

よく使われる例だが、平面図形を表すShapeクラスを作り、この図形を描画するDrawメソッドを持たせたとしよう。
Shapeは抽象クラスなので、Drawは派生クラスであるRectangleとかCircleとかTriangleといったクラスによって実装される。
ここで、「同じDrawメソッドでも、RectangleとCircleでは違う挙動を示す」ことが「多態性」だと言われる。
これをめぐって、脳内で甲と乙が言い合いをしている。

甲:
Rectangleクラスは、メンバとして縦の長さと横の長さを持っている。それらの値が違えば、描かれる図形は当然異なる。
一方のインスタンスは1cm×1cmの正方形を描き、もう一方のインスタンスは3cm×5cmの長方形を描いたとき、これは「同じDrawメソッドでも挙動が異なる」ことにはならないのだろうか。
乙:
Rectangleクラスは「長方形」でしかない以上、Drawメソッドの効果は「長方形を描く」ということだけだ。描かれた結果を抽象してみれば、どちらも長方形を描いていることに変わりはないのだから、同じ挙動であると言える。
甲:
なるほど、Rectangle.Drawの意味は確かに「長方形を描く」であるかもしれない。だとすれば、Circle.Drawは「円を描く」であり、Triangle.Drawは「三角形を描く」だ。
ところで、多態性とは「同じメソッドであっても、クラスが違えば挙動が違う」であった。しかし、クラスが違えばメソッドの意味が違ってくることは今見たとおりだ。
さて、Rectangle.DrawとCircle.Drawは何を以てして「同じメソッドである」と言えるのだろうか。
乙:
多態性と継承は切っても切れない関係にある。
確かに、Rectangle.DrawとCircle.Drawの意味は違う。しかし、
Shape s = new Rectangle();
s.Draw();
Shape s = new Circle();
s.Draw();
では、呼び出しているのはどちらもShape.Drawでありながら、その結果が異なる。
「派生型は基底型を通じて参照できる」という原則のもとでは、「同じメソッド」と言えるだろう。
甲:
先程、Rectangle.Drawは単に「長方形を描く」メソッドに過ぎないのだから、実際に描かれた図形が、どうであれ長方形である以上、その大きさは問題にならないとした。
その理屈を適用すれば、Shape.Drawの意味は「平面図形を描く」ということだけだ。ということは、結果として描かれたものが長方形であれ円であれ、「違う挙動」とは言えないのではないだろうか。
乙:
同じShape.Drawを呼び出していながら、RectangleとCircleでは実行されるコードが異なるのだから「違う挙動」である。
甲:
では、Rectangle.Drawのコードが以下のようになっていたとしたらどうか。
if( 縦の長さ == 横の長さ )
{
 正方形を描く();
}
else
{
 長方形を描く();
}
これでも、1cm×1cmの場合と3cm×5cmの場合とで「同じコードが実行されている」と言えるか?
乙:
その通り。途中で分岐していようが、全体としてRectangle.Drawが実行されているのだから、どちらのケースも単一のRectangle.Drawである。
甲:
なるほど。メソッドの入口と出口さえ共通であればよいと。
では、Shape.Drawが実行される様子を想像しよう。
  1. クライアントがShape.Drawを呼ぶ
  2. Shape.DrawはRectangle.Drawを呼ぶ
  3. Rectangle.Drawが終わったら、呼び出し元のShape.Drawに戻る
  4. Shape.Drawからクライアントに制御が返る
このような実装方式になっていた場合、中身がRectangleだろうがCircleだろうが、入口と出口はともにShape.Drawで共通である。
全体としてShape.Drawが実行されているのだから、「違う挙動」とは言い難い。
それとも、このように実装されたものは多態性と呼ばないとでも言うか?
乙:
実際に描画しているコードが異なるのだから違う挙動である。
甲:
先程言ったことと矛盾している。
実際に描画するロジックが何であれ、総体としてRectangle.DrawならばRectangle.Drawであると言ったばかりではないか。

なんだか甲が有利だ。
当議論は、あなたの乱入をお待ちしております!

投稿日時 : 2007年5月9日 14:18

Feedback

# re: 【思考実験】ポリモーフィズム 2007/05/09 14:45 囚人

まぁ、ケースバイケースでしょうね。

例えば、長方形の辺の「cm」が違う毎に違うクラスにすると大袈裟に感じますが、「大きい長方形を書くクラス」「中くらいの長方形を書くクラス」「小さい長方形を書くクラス」という区別ならば別クラスにしてそれぞれポリモーフィック、としてもよいかもしれません。

なので、「形が違うという事が設計上重要」ならば乙さんが正しいし、「形や大きさが違うという事が設計上重要」ならば甲さんが正しい。そして「図形を書く」という挙動が同じなのでポリモーフィック。

# re: 【思考実験】ポリモーフィズム 2007/05/09 14:59 じゃんぬねっと

> その通り。途中で分岐していようが、全体としてRectangle.Drawが実行されているのだから、どちらのケースも単一のRectangle.Drawである。

これと、

> 全体としてShape.Drawが実行されているのだから、「違う挙動」とは言い難い。
> それとも、このように実装されたものは多態性と呼ばないとでも言うか?

これを同じ舞台にしちゃいけないのではないですか?
一般的に言われるポリモーフィズムとは関係ないものと比べてませんか?

> これでも、1cm×1cmの場合と3cm×5cmの場合とで「同じコードが実行されている」と言えるか?

こういう分け方はしないと思いますけど。(例に突っ込みを入れてもしょうがないですが)

> その通り。途中で分岐していようが、全体としてRectangle.Drawが実行されているのだから、どちらのケースも単一のRectangle.Drawである。

ここでいう単一の Draw メソッドの条件分岐と、

> このような実装方式になっていた場合、中身がRectangleだろうがCircleだろうが、入口と出口はともにShape.Drawで共通である。
> 全体としてShape.Drawが実行されているのだから、「違う挙動」とは言い難い。
> それとも、このように実装されたものは多態性と呼ばないとでも言うか?

Shape.Draw からのデータ型による分岐は、意図が違うのではないでしょうか。
後者はポリモーフィズムであるがゆえの、つまりクラス内のメソッドレベルでの多態ですが、前者はメソッド内のロジックレベルの多態ですよね。

シャノンさんはいつも何かしろの根拠を持っているので、私の方が自信がなかったりするわけですが何か読み違いしていますか?

あ、そっか 「形」だけでなく 「大きさ」の問題もあるのか。
やべぇ、自信ねぇwwww

# re: 【思考実験】ポリモーフィズム 2007/05/09 15:35 とっちゃん

面白いので参戦。

丙(ライブラリユーザー):
ごちゃごちゃうるせー!俺にいわせれば全部「図形」だ!

甲乙:図形言うなー!

丙:お、同じじゃねーか!何が違うんだ!丸も資格も参画も...あ、ちがった。
丸も四角も三角もみんな図形じゃないか。
ちょっとくらいとがってる数がちがっても大差ねーよ!

だって俺が使ってんのは、

private void OnMenuShape(object sender, EventArgs e)
{
Shape s = CreateShapeFromEventArgs( e );
s.Draw();
}
だぞ!四角も丸もねーよ!
おまえらがこれでいいって言ったんじゃないか!!!

# re: 【思考実験】ポリモーフィズム 2007/05/09 15:39 シャノン

乙の3回目以降の発言は苦し紛れですww

# re: 【思考実験】ポリモーフィズム 2007/05/09 15:42 シャノン

> 一般的に言われるポリモーフィズムとは関係ないものと比べてませんか?

一般的に言われるポリモーフィズムの説明として「同じメソッドでもクラスが違えば挙動が異なること」というのが適当ではないのではないか、という問題提起です。

# re: 【思考実験】ポリモーフィズム 2007/05/09 15:44 とっちゃん

し、しまった。続き書き忘れたw

作る側の視点で、ポリモーフィズムを語ってはいけません。

ポリモーフィズムを語るときは「いかなる理由があろうとも」「必ず」「使う側の視点」で語る必要があります。

ポリモーフィズムは見せ方のテクニックです。
作る側の理論を持ち込んできた時点で既に水かけ論ですw

# re: 【思考実験】ポリモーフィズム 2007/05/09 15:48 なちゃ

使う側が区別なく使える。
共通の使い方だけ知ってればいい。
中身はそれぞれ勝手にやってくれる。

プログラミング方法としてとても便利で分かりやすい(慣れたら)。

オブジェクト指向的にどういう意味とかなんてどうでもいい。
と、ぶっちゃけそう思います。

# re: 【思考実験】ポリモーフィズム 2007/05/09 16:55 じゃんぬねっと

> 乙の3回目以降の発言は苦し紛れですww

うん、シャノンさんらしくないなとは思いました。

> 一般的に言われるポリモーフィズムの説明として「同じメソッドでもクラスが違えば挙動が異なること」というのが適当ではないのではないか、という問題提起です。

なるほど、そうやって明示的に書いとくれないと私みたいな頭の悪い人は真面目にわかんないですよw

# なちゃさんからコメントつけてもらえるなんて羨ましいな。

# re: 【思考実験】ポリモーフィズム 2007/05/09 19:01 シャノン

> ポリモーフィズムを語るときは「いかなる理由があろうとも」「必ず」「使う側の視点」で語る必要があります。
> オブジェクト指向的にどういう意味とかなんてどうでもいい。

その考えで行くと、ダックタイピングになっちゃう気がするのですよ。
オブジェクト指向の三本柱の一つと言われる「ポリモーフィズム」とは、ダックタイピング的ポリモーフィズムなのか…な?

# re: 【思考実験】ポリモーフィズム 2007/05/09 19:10 とっちゃん

俺的なポリモーフィズムは
>ポリモーフィズムは見せ方のテクニックです。
です。

なので、どう見せる?どう使わせる?という点があって
その上で、使う側からみてどれだけものを考えずに済むか?
というのが本質だと思っています。

要はブラックボックス化の一つの表現方法だとw

なので、使う側からすればダックタイピングとかなり近いです。
それを形成する技術的な面が同じかどうかはともかくですがw

# re: 【思考実験】ポリモーフィズム 2007/05/09 22:34 かずくん

ポリモ?フィズムとは、近視状態みたいなもの。
何か線を引いてる(draw)ような気がするけど、「俺、目悪いから一体どんな線引いてるかまではよくわからない」そんな感じ?
出来上がった結果を凝視してみたら、三角形だった、または円形だったと。

この辺をふまえて、甲や乙に対して異論・反論・オブジェクション!
> 一方のインスタンスは1cm×1cmの正方形を描き(snip)
> これは「同じDrawメソッドでも挙動が異なる
ぼやっと見える状態では、「向かい合う辺が平行で、隣り合う辺は直角な気がするから」同じ挙動。

>Rectangle.DrawとCircle.Drawは何を以てして「同じメソッドである」
ぼやっと見える状態では、線を引いているという点

>結果として描かれたものが長方形であれ円であれ、「違う挙動」
まぁ、結果としてはそうゆうことになるね。よく見ないとわからなかったけど。

> 1cm×1cmの場合と3cm×5cmの場合とで「同じコードが実行されている」と言えるか?
同じなんじゃないの?ぼやけてて、細かいところは、よく見えてないから実際のところわかんないけどw


# re: 【思考実験】ポリモーフィズム 2007/05/09 22:36 かずくん

私にとっては、四角形を描くことも、三角形を描くことも、円形を描くことも、どれも違う挙動とは思えない。

さすがに、線を引くこと(draw)と、くじを引くこと(draw)は違う挙動とは思うが。

# re: 【思考実験】ポリモーフィズム 2007/05/09 22:44 かずくん

> さすがに、線を引くこと(draw)と、くじを引くこと(draw)は違う挙動とは思うが。
ダックタイピングの世界では、これも同じ挙動にされるのかな?

# re: 【思考実験】ポリモーフィズム 2007/05/09 23:31 黒龍

すんげー遅れた・・・。

>2 Shape.DrawはRectangle.Drawを呼ぶ
ってのじゃなくてRectangle.DrawがShape.Drawのふりをしてるわけなので2はすっ飛ばすイメージっす。
Shapeの振りをしたRectangleがRectangle.Drawを呼ばれるとおもっちょります。

# re: 【思考実験】ポリモーフィズム 2007/05/10 0:28 シャノン

> ってのじゃなくてRectangle.DrawがShape.Drawのふりをしてるわけなので2はすっ飛ばすイメージっす。

そういう実装もあるでしょうし、こういう実装もあるでしょうね。
どちらにせよ、乙の3回目以降はあまり重要ではないのですがw

# re: 【思考実験】ポリモーフィズム 2007/05/10 0:31 シャノン

> 私にとっては、四角形を描くことも、三角形を描くことも、円形を描くことも、どれも違う挙動とは思えない。

そこで問題になるのは、共通クラス Shape がなくて(あるいは、Shape はあるけど Rectangle とかの基底クラスじゃなくて)、四角形と三角形と円クラスが全く相互に関連がない(けど、Draw メソッドのシグネチャだけは偶然同じ)でも成り立つのかということです。

# re: 【思考実験】ポリモーフィズム 2007/05/10 9:37 かずくん

> 全く相互に関連がない(けど、Draw メソッドのシグネチャだけは偶然同じ)でも成り立つのか
静的(コンパイル時)なのか、動的(実行時)なのかの違いだけで、どちらも成立すると思ってます。

# re: インターフェイスって何? 2007/05/15 13:11 R.Tanaka.Ichiro's Blog

re: インターフェイスって何?

タイトル
名前
Url
コメント