C++の継承が難しい
C#みたいなインターフェイス指向?(という単語があるのか知らないが)なコードをC++で書こうとして継承が分からなくなった。
とりあえずこんなインターフェイスを用意。
IBaseを基底として、IA、IBがそれぞれ別のインターフェイス。
この時に、IBaseの処理は同じなので1つの実装を継承して使いまわそうと計画。
まずはC#の場合。
コードはこんな感じ
interface IBase { void MethodBase(); } interface IA : IBase { void MethodA(); } interface IB : IBase { void MethodB(); } class BaseImpl : IBase { public void MethodBase() {} } class AImpl : BaseImpl, IA { public void MethodA() {} } class BImpl : BaseImpl, IB { public void MethodB() {} }
これをまんまC++で実装したら
class IBase { public: virtual void MethodBase() = 0; }; class IA : public IBase { public: virtual void MethodA() = 0; }; class IB : public IBase { public: virtual void MethodB() = 0; }; class BaseImpl : public IBase { virtual void MethodBase(){} }; class AImpl : public BaseImpl, public IA { virtual void MethodA() {} }; class BImpl : public BaseImpl, public IB { virtual void MethodB() {} };
でビルドするとエラー
エラー 1 error C2259: 'AImpl' : 抽象クラスをインスタンス化できません。
IAもIBaseを継承してるから、共通の基底クラスから菱形の多重継承になっちゃってる訳です。
じゃぁってことでvirtual継承にします。
class IA : virtual public IBase { public: virtual void MethodA() = 0; }; class BaseImpl : virtual public IBase { virtual void MethodBase(){} }; class AImpl : public BaseImpl, virtual public IA { virtual void MethodA(){} };
すると今度は
warning C4250: 'AImpl' : 2 つ以上のメンバが同じ名前を持っています。'BaseImpl::BaseImpl::MethodBase' から継承します。
warning なのでモノはできるものの、毎回でると気分がよろくしない。
いろいろとこねくり回した結果、多重継承をやめるという結論に。
template<class Interface> class BaseImpl : public Interface { virtual void MethodBase(){} }; class AImpl : public BaseImpl<IA> { virtual void MethodA(){} };
このやり方の問題は、IAとIBを継承したクラスを作ろうとしたらAImplもテンプレートにしないといけないとかとか。
インターフェイス指向的のC++な実装がわかりません。