C言語を使ってた時代に関数の引数に文字列や構造体を使用する場合、文字列や構造体のポインタを用いていた。オブジェクト指向言語を使うようになってからは、クラスから生成されたインスタンスというものを使用できるようになったので、様々なクラス型のデータもポインタを使わずにメソッドの引数として用いることができるようになった。ここまで考えると、オブジェクト指向の大筋って、ポインタを用いずに、クラスから生成されたインスタンスを利用して、多種のデータ型に対応できるのとが特徴って言えると思う。
methodA (classA instanceZ) {
instanceZ.method1() ;
instanceZ.method2() ;
}
この例のmethodA は classA型のinstanceAのmethod1とmethod2を実行している。classAというのは、データ型だけではなくmehod1とmethod2というメソッドも実装している。もしclassAがデータのみであれば、構造体と同じようなプログラミングをすればよい。しかしメソッドを含んでいるという点で、オブジェクト指向ならではのプログラミング作法が存在する。
classBに同じ名前のメソッド method1, method2 を実装させてみる。メソッド名は同じでも、メソッドの内容は変えて記述し、methodAの実行動作を変化させることができる。
methodA (classB instanceZ) {
instanceZ.method1() ;
instanceZ.method2() ;
}
これがclassB型のインスタンスを引数としたmethodAの例であるが、メソッド内部の記述はそっくり同じで済むが、メッソド引数のクラス型がインスタンスに異なる。
ここで、classXを定義し、classA, classB の基底クラスとする。つまり、classA, classB はclassXを継承する。そうすることにより、classAのインスタンスを引数とする場合もclassBのインスタンスを引数とする場合も以下のように共通の記述で済む。
methodA (classX instanceZ) {
instanceZ.method1() ;
instanceZ.method2() ;
}
インスタンス引数には、必ずクラス型を宣言しないとコンパイルエラーになるっていう言語制約があるために、基底クラスを作って、そこから継承して派生クラスを作るということをします。これがつまり、オブジェクト指向信者が愛してやまないポリモーフィズムです。
methodAを実行させるには、
methodA(classAによって生成されたインスタンス)
または
methodA(classBによって生成されたインスタンス)
となります。methodAには手を加えず、呼び出し側だけ追加していけば実装できます。
しかし、型宣言を省略できる言語では、ポリモーフィズムを実現するために、基底クラスから継承など必要なのか、はなはだ疑問です。型宣言はその言語特有の仕様上の作法の問題ですよね。
もちろん共通部分の記述を省略するための継承は、インクルード使わない限りはあったほうがいいですよね。でもそういうことは当たり前のことで、多くのオブジェクト指向信者が熱狂しているのは、ポリモーフィズムを利用する場合の継承に特化してるように思えます。
ポリモーフィズムやインターフェイスについては、プログラムのメンテナンスや拡張にかかわる技術であって、それは言語仕様や開発環境により常に何なベストなのか時代ともに変化してしまいます。開発者は過去の都市伝説的な記事に惑わされれずに、実践を通じて何が効率的なのか常に追求していかなれればなりません。