C++で静的ポリモーフィズムを実現したい場合には、テンプレートを用いる必要があります。派生クラスに相当する型をテンプレートクラスのメンバ変数として包含させることでこれを実現します。
包含を用いた静的ポリモーフィズム
// テンプレートクラス
template<class T> struct Animal {
T animal; // 派生クラスに相当する型を包含
void nadeNade() { animal.cry(); animal.cry(); }
};
// 派生クラスに相当する型
struct Cat { void cry() { puts("にゃん"); } };
struct Dog { void cry() { puts("わん!"); } };
int main() {
Animal<Cat>().nadeNade(); // "にゃんにゃん"
Animal<Dog>().nadeNade(); // "わん!わん!"
}
この形態はいわゆる「has-a関係」に相当するものです。ただし完全な多態性を実現するものではなく、あくまで静的なポリモーフィズムを体現するためのレトリックとなります。
他にも、テンプレート引数による再帰的な継承テクニックを用いて静的ディスパッチを実現する方法もあります。これによって、より一般的な継承のスタイルに近い形での静的ポリモーフィズムを実現することが可能になります。
template<class T> struct Animal {
void f() { static_cast<T*>(this)->g(); }
};
struct Cat : Animal<Cat> { void g() { puts("にゃん"); } };
struct Dog : Animal<Dog> { void g() { puts("わん"); } };
Cat().f(); // "にゃん"
Dog().f(); // "わん"
また、テンプレートの特殊化を用いて処理のバリエーションを実現するようなこともできます。ただし一般的な方法ではなく、大したメリットもないため、参考程度に紹介しておきます。
enum Animals { Cat, Dog, Fox };
template<Animals> struct Animal {
void f() { g(); }
void g() { puts("・・・"); }
};
template<> void Animal<Cat>::g() { puts("にゃん"); }
template<> void Animal<Dog>::g() { puts("わん!"); }
template<> void Animal<Dog>::f() { printf("わん"); g(); }
Animal<Cat>{}.f(); // "にゃん"
Animal<Fox>{}.f(); // "・・・"
Animal<Dog>{}.f(); // "わんわん!"