C++ で ダック・タイピング

C++ ではメソッドの名前が同じでも返り値が違うと継承時にオーバーライドできない(当たり前だけれど).例えば以下の様に,親子関係にある二つのクラスでそれぞれの配列を作るとする.

class BaseObj { ... };
class DerivObj : public BaseObj { ... };

class BaseArray {
  virtual BaseObj* Get(int index) { /* Get の実装 */ }
};
class DerivArray : BaseArray {
  virtual DerivObj* Get(int index); /* 上の実装を再利用したい */
}

Array クラス内でどのように配列を持つかは任意としても,きっと BaseArray と DerivArray は対象のオブジェクトが違うだけで,内容はほとんど一緒になるだろう.当然の思いとして,上のように DerivArray で BaseArray を継承しようと考える.
だけれど,これはエラーになる.なぜなら,BaseArray::Get と DerivArray::Get は返り値が違うのでオーバーライドできず,でも名前が一緒なのでオーバーロードの関係になってて,戻り値しか違わないのでオーバーロードできずコンパイルエラーになる.実装は再利用したいけれど,継承では解決できない.
そこで華麗に登場するのがダック・タイピングという手法.俺もさっき知った.そうそう,俺がやりたかったのはこういうことなんだよ!

ダックタイピングとは ... オブジェクトがあるインタフェースのすべてのメソッドを持っているならば、たとえそのクラスがそのインタフェースを宣言的に実装していなくとも、オブジェクトはそのインタフェースを実行時に実装しているとみなせるということである

http://ja.wikipedia.org/wiki/%E3%83%80%E3%83%83%E3%82%AF%E3%83%BB%E3%82%BF%E3%82%A4%E3%83%94%E3%83%B3%E3%82%B0

つまり,オーバーライドの関係になくても,同じ名前なら同じようにメソッドを呼び出せる,ということ.C++ の場合は,静的ならば(コンパイル時に型が決まるならば)テンプレートを使ってできるみたい.
これを参考に,上のコードを書き換えると次の様になる.

class BaseObj { ... };
class DerivObj : public BaseObj { ... };

template <class Obj> class Array {
  Obj* Get() { /* Get の実装 */ }
};

// テンプレートのインスタンス化
template class Array<BaseObj>;
template class Array<DerivObj>;

class BaseArray : public Array<BaseObj> {
}
class DerivArray: public Array<DerivObj> {
}

コードのコピペをコンパイラにやらせている感じ.上の例では結局やっていることは C++ STLvector と一緒なのだけれど,ちょっと考えれば対した発想でもないような気もするけれど,自分にとってはコロンブスの卵だった.今まで気づかず損をしていたなあ.これは感動した.