2017-01-12 13 views
3

tl; dr - 構図は私の状況にとって正しいデザインの選択のようですが、一緒に作っている各オブジェクトのヒープ割り当てのオーバーヘッドを避けたいと思います。どんな良いテクニックですか?合成(過剰継承)による余分なヒープ割り当ての回避

私は次のようになり、セットアップがあります。

大体
class Foo { 
    public: 
    Foo(unique_ptr<FooEvaluator> evaluator) 
    : evaluator_(std::move(evaluator)), 
     common_state_() {} 

    void FooMethod() { 
     // Perform some common processing. 
     evaluator.DoSomething(); 
    } 
    private: 
    unique_ptr<FooEvaluator> evaluator_; 
    Bar common_state_; 
} 

class FooEvaluator { 
    public: 
    virtual void DoSomething() = 0; 
} 

class FooEvaluatorImpl : public FooEvaluator { 
    public: 
    FooEvaluatorImpl(type1 arg) {...} 

    void DoSomething() override {...} 
} 

class FooEvaluatorImplVariant : public FooEvaluator { 
    public: 
    FooEvaluatorImplVariant(type2 arg) {...} 

    void DoSomething() override {...} 
} 

を:私はいくつかの共通の処理を行うのFooを持っているし、その後FooEvaluatorを使用しています。私はいくつかの異なるロジックを持つFooEvaluatorの実装をいくつか持っています。一般的なFoo処理は、それを複製しないようにするのには意味がありますが、それほど重要ではありません。

共有ロジックと評価ロジックの両方を含むモノリシックなFooを使用していた場合は、2つのオブジェクトを割り当てる必要があります。

FooからFooEvaluatorを継承し、Fooのプライベート仮想メソッドとしてDoSomething()を追加することは、ぼんやりとした妥当な中間地です。これは継承の濫用のビットです(あなたはFooEvaluatorが "Foo"だとは言えませんが)、私の共有コードを取得し、倍精度メモリの割り当てを回避します。

どのような考えですか?まあ

+0

はFooの評価者のほぼ同じ大きさのすべてはありますか?もしそうなら、私はそれらをstd :: variantまたはboost:variantにして、通常は仮想関数インタフェースであるものを実装するvisitor関数を持っています。 – RyanP

+0

仮想継承をcrtpに置き換えることはできますか?つまり、コンパイル時にコンポジションを実行できますか?これは、タイプ消去を失うのと引き換えにunique_ptr、ヒープ割り当て、およびvtableを削除します(またはレベルを上げる)。 –

+0

「構成」の意味が分かりません。あなたは例を挙げることができますか?私は構成がどのように複数の割り当てをもたらすか理解していません。 (おそらく私の無知だろうが) –

答えて

2

あなたはテンプレートを使用してそのような何かを行うことがあります。

template <typename Evaluator> 
class Foo { 
public: 
    template <typename ... Ts> 
    Foo(Ts&&... args) 
    : evaluator_(std::forward<Ts>(args)...), 
     common_state_() 
    {} 

    void FooMethod() { 
     // Perform some common processing. 
     evaluator.DoSomething(); 
    } 
private: 
    Evaluator evaluator_; 
    Bar common_state_; 
}; 
+0

これは、これまでのところ最も良い解決策のようです。誰かが何か別のものを提案しているかどうかを確認するために、1日は受け入れられないようにしておきます。 – mfrankli

-1

、私はFooのの複雑/詳細については考えていることから、私はそれインライン関数作る示唆し、その後、あなたが実行する前に、共通の処理を達成するために、いくつかのFooEvaluatorインスタンスからそれを呼び出すことができます詳細。

+0

詳細の不足について申し訳ありません - Fooにはいくつかの状態がありますが、残念ながらこれは動作しません(私は思いますか?) – mfrankli

+0

はい、あなたは正しいです。あなたは '共通処理'を基本FooEvaluatorクラスに移動できません。 Fooを削除し、状態を含むBarクラスのみを保持し、処理を実行するのに必要な既存の状態情報を参照するために、FooEvaluatorインスタンスにBar *を持たせます。 –

関連する問題