2010年03月31日

OOP その4 ポリモーフィズム ダイナミックバインディング

【注意】素人が迷走しながら書いてる記事なので参考にしないで下さい(苦笑)

ポリモーフィズム(多態性)


スーパークラスとサブクラスの関係で、同じ名前のメソッドでもオブジェクトによって処理内容を変更できる仕組みのこと。
継承で書いた「サブクラスを作成する際に、拡張(追加)とオーバーライド(変更)が出来る」このことと関係している。

CS3ドキュメンテーション 継承

上の記事からの引用
継承を使用すると、コード内で "ポリモーフィズム" を利用することもできます。
ポリモーフィズムを使用すると、異なるデータ型に適用された場合に異なる動作を実行するメソッドに単一のメソッド名を使用できます。
単純な例として、2 つのサブクラス Circle と Square を持つ Shape という名前の基本クラスがあります。
Shape クラスは、形状の面積を返す area() というメソッドを定義します。
ポリモーフィズムが実装されている場合、Circle 型および Square 型のオブジェクトで area() メソッドを呼び出して、正しい計算を行うことができます。
継承では、サブクラスが基本クラスからメソッドを継承し、再定義できるようにする、つまりオーバーライドを許可することで、ポリモーフィズムが有効になります。


なるほど!と思えたけど、取っ付き難い文章なので書き換えてみる。
Shapeクラスを拡張してareaという名前の面積を計算するメソッドを作る。
Shapeクラスをスーパークラスとした、Circleクラス(円)とSquareクラス(正方形)の二つのサブクラスを作る。
この両方にareaメソッドを継承したい場合。

円の面積の求め方は、半径×半径×円周率
正方形の面積の求め方は、辺の長さ×辺の長さ

同じareaという名前のメソッドを作るけど、Shapeクラスからそのまま継承しただけでは、間違った解になってしまうので、それぞれ違う計算方法を書かないといけない。
そこで、オーバーライド(変更)を許可して、areaメソッドを継承して、Circleクラスのareaメソッドには円の面積の求め方を書き、Squareクラスのareaメソッドには正方形の面積の求め方を書く。

まぁ、継承にもいろいろ決まりごとがあるようですが、それはまた別の機会に勉強することにします。


ダイナミックバインディング(動的型付け)


対義語で「静的型付け」というのがある。
これは「型」のお話なんだけど、どの時点で「型」が決まるかで違いがあるらしい。
んで、JAVAとかC#は「静的型付け言語」で、アクションスクリプトは「動的型付け言語」というふうに、言語によって違うらしい。
JAVAなど知ってる人は違いが解るのかもしれないけど、私は他の言語を知らないのでちょっと難しい。。。

例えば、アクションスクリプトで型指定をしていない変数hogeを作成したとする。
hoge=10;
としたら、hogeはNumber型になる。
hoge="10";
としたら、hogeはString型になる。
このように、実行した段階で型が決まることを「動的型付け」というのだと思う。
静的だと、エラーが出るってことかな?

Stringとして扱いたいのに、誤って数値として代入してしまった場合、動的だとエラーにならないので、関連プログラムを実行するまでバグに気づかない。
これが動的型付けの弱点らしい。


まぁASでもhoge:Number="10";ってするとコンパイルエラーが出るんですけどね。
おもしろいので、ついでにこんなこともしてみた。
var hoge:Number;
hoge = "10" + 10;
trace(hoge);
trace(typeof(hoge));

さて出力結果はどうだったでしょうか?

hogeの値=1010
hogeの型=number

コンパイルエラーにはならずに、値はストリングの足し算と同じ結果になって、データ型はnumberのままでした。
つまりhogeには1010という数値が入っているんですね。
じゃぁ、hoge="A"+10; としたらどうかな?

hogeの値=NaN
hogeの型=number

NaNとは、非数。つまり数にあらず(非ず)ってことだから、数値として表示できないってこと。
ちなみにNumber型のデフォルト値はNaN

これらの出力結果は、ごもっともだけど、"10"+10とか、つい、やらかしてしまうミスでもあるよね。。。
でも、こういう風にかくと、ちゃんとコンパイルエラーが出るんだよね。
var hoge:Number;
hoge = 10;
hoge += "10";

これで型指定しなかった場合は、1010のString型になっちゃう。
あるいは、hoge += Number("10"); と書いたら、値は20でNumber型になる。

だから、変数やインスタンスを生成するときは、ちゃんと型指定しようねってことなんだろうな。

あれ?なんか話が脱線してる?(笑)
いや、そうでもないか。
型指定することで、ある程度、動的型付き言語の弱点が補えるってことだよね。たぶん。


posted by K at 10:33| Comment(1) | OOP | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
こんばんは。

後半のコンパイルエラー関係のお話は、あいにくASは存じ上げないのですが、オブジェクト指向的にはこういう事だと思います:

(1)「"10"」(という値の無名の)文字列オブジェクトが作られます。
(2)そのオブジェクトの「+」メソッド(文字列の連結を行う、文字列クラスのメソッド)が、「10」をパラメータとして実行されます。
(3)結果として、「"1010"」という値の文字列オブジェクトができます。
(4)hogeの「=」メソッド(代入を行う、数値クラスのメソッド)が、さっきの「"1010"」をパラメータとして実行されます。
(5)パラメータの「"1010"」が、数値の「1010」とみなされて、hogeに格納されます。

同様に、「"A"+10」の場合は「"A10"」となって「NaN」に変換されたのでしょう。
また、変数の型を指定しなかった場合(というより、型の指定を省略した場合)は、全てのクラスの共通のスーパークラス(つまり、オブジェクトクラス)が指定されたとみなされるのだと思います。
Posted by くろょ at 2012年06月10日 00:19
コメントを書く
お名前: [必須入力]

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。