2016-11-17 26 views
1

プロジェクトでは、ライブラリのインターフェイスから実装の詳細を隠す必要があります。この「効率的な」(コーディングとメンテナンスの面で)私が扱う唯一の方法は、同じ抽象基盤に基づく抽象クラスと具象基底クラスの複数の継承でした。だから、私は拡張されたダイヤモンド構造で終わった。C++多重継承/仮想継承

私は通常、複雑であるため可能な限り複数の継承を避けようとしていますので、使用経験はあまりありませんので、私が試しているデザインに落とし穴がありますか?監督しません。

基本的に私は複数の「ツール」を用意する必要があります。これらの「ツール」にはもちろん、インターフェイスABCを使用して非表示にしたい実装の詳細があります。例:

class Tool1Impl:public ITool1;

クラスTool2Impl:public ITool2;

もちろん、ツールにはいくつかの共通点があります。

私は共通の基本クラスを持ちたいと思いますが、インプリメンテーションの詳細はインターフェイスで再度隠す必要があります。

私は、次の(ダイヤモンド)方式を思い付いた:

  ITool           
     / | \    
     / |  \ 
    /  |  \ 
ITool1 ToolImplBase ITool2 ... IToolN 
    \  / \ /
    \ /  \ /
    \ /  \/
    ToolImpl1  ToolImpl2 ... IToolImplN 

ToolImplBaseはのiToolの純粋仮想機能を実装しています。 ToolImpl1は、ITool1で宣言された純粋な仮想機能を実装します。

実装のアウトラインは以下のようになります。

class ITool { 
public: 
    virtual int common_foo(int a) = 0; 
}; 

class ITool1 : public virtual ITool { 
public: 
    virtual int specific_foo(int b) = 0; 
}; 

class ITool2 : public virtual ITool { 
public: 
    virtual int specific_bar(int c) = 0; 
}; 

class ToolImplBase : public virtual ITool { 
public: 
    virtual int common_foo(int a) override; 
protected: 
    int _some_common_data; 
}; 

class ToolImpl1 : public ToolImplBase, public virtual ITool1 { 
public: 
    virtual int specific_foo(int b) override; 
private: 
    int _some_specific_data; 
}; 

class ToolImpl2 : public ToolImplBase, public virtual ITool2 { 
public: 
    virtual int specific_bar(int c) override; 
private: 
    int _some_specific_data; 
}; 

私がやりたいようだが、これですべての潜在的な落とし穴や明白な問題があった場合、私はわかりません。私は、もし私が継承スキームのすべての権利(仮想メソッドではなく ":public virtual")で "仮想"を取得しているかどうかもわかりません。

warning C4250: 'ToolImpl1': inherits'ToolImplBase::ToolImplBase::common_foo' via dominance 

は、私はちょうどそれを無視することができます: 1つの問題は、MSVCは(私が原因。この時点で、いくつかの外部depenciesに2010とこだわっている)私のコンパイラの警告C4250を与えること、ありますか?なぜcommon_fooへの非支配的な方法は純粋な仮想であるので、私はなぜこれを得ているのかは分かりません。したがって、実際には有効でない "支配的でない"実装はありません。任意の入力のための

おかげで(を除いて「 M.I.を使用することはありません」、私はすでに、可能な限りそれを避けるためにしようとしています)。

+1

私の小さなビット以下のようにIToolXインターフェイスを変更します:必要なときにMIを使用すること自由に感じていますがダイヤモンドを持っているとき、あなたは間違った道に、おそらくです。あなたは、意味の代わりに結果を得るために継承を使用していないと確信していますか? ToolImplBaseの2つのことを考えてみましょう(例は架空のものなので、これ以上は言えません):構成と私的継承。 –

+0

この例は架空のものではなく、実際のコードのものですが、もちろん簡略化されています。あなたはここでそのコンポジションをどのように使用しますか? ToolImplFoo内のIToolからの共通の機能をすべてToolImplBaseに委譲するだけですか? –

+0

C4250関数 'common_foo'は2つのパスに継承されており、異なる実装を持っています。最終形式で実装する必要があります – Danh

答えて

0

ここで警告に関するいくつかの説明があります:What does C4250 VC++ warning mean?

私はあなたがインターフェイスとしてITool1を設計しているため、あなたのコードに問題はないと思います。

ITool1common_foo関数を実装すると、ToolImpl1を作成するときにcommon_fooのどの実装が動作するかわかりません。

問題には注意が必要ですが、誰でも合法的にIToolXの実装でcommon_fooの機能を実装してもエラーは発生しません。

私の最終的なコメントは、ITool1IToolから派生する必要がある理由は何ですか? ToolImpl1は既にToolImplBaseから派生しているため、実際の実装クラスは常にIToolから派生します。

私は

class IToolX{ 
    public: 
    virtual int specific_foo(int b) = 0; 
}; 
+0

ありがとう、私は一般的にC4250を理解しましたが、実際には "Interface"パスに実装されていないため、この特殊なケースではありません。あなたの質問に関して:ITool1をIToolから派生させたいと思います。私が言ったように、私はユーザから実装の詳細を隠したいからです(これは図書館です)。 "ユーザー"は決してToolImplXではありませんが、常にIToolXです(私はおそらく、コンストラクターは保護されていると言わねばならないでしょうし、Factoryクラスを持っています:ITool1 * createTool1(){return new ToolImpl1();} –

+0

プロジェクトに参加しても問題のない設計上の意思決定はいつでも記憶されますが、他の誰かがコードを管理している場合、または数ヶ月後に新しいツールを追加する必要がある場合には問題が発生する可能性があります。 – cokceken

+0

:期待?メンテナが元のデザインを理解していないため、誰かがそれを裂くと問題が起きる可能性があることは、すべてのコードで真実ではありませんか? IMHOは明示的なコードコメントのためのものです... –