3


このような問題にどのように対処するかを知りたいです。

私はクラスを持っていますFoo

class Foo
{
public:
    Foo()  {   }
    ~Foo() {   }
    float member1() { return _member1; }
private: 
    float _member1;
    // other members etc...
}

とりわけ、Foo インスタンスへのポインターのコンテナーを保持するコンテナー クラス

class FooContainer
{
public:
   FooContainer() {   }
   ~FooContainer() {   }
   void addFoo(Foo* f) {_foos.push_back(f);}
private:
   boost::ptr_vector<Foo> _foos;
}

私の問題は次のとおりです。実行時に、GUI からの指示に応じて、新しい (まったく異なる) メンバーを Foo に「追加」する必要があります。次のような 2 つの「デコレータ」を作成することで、この問題に対処できます。

class Decorator1
{
public:
   int   alpha() { return _alpha; }
   float beta()  { return _beta; }
private:
   int _alpha;
   float _beta;
}

class Decorator2
{
typedef std::complex<float> cmplx;
public:
   cmplx  gamma() { return _gamma; }
   double delta()  { return _delta; }
private:
   cmplx  _gamma;
   double _delta;
}

次に、2 つの異なる Foo 実装を作成します。

class Foo1 : public Foo, public Decorator1 
{   }

class Foo2 : public Foo, public Decorator2 
{   }

GUIコマンドに従ってそれぞれを使用します。ただし、このような変更はすべてのコードに反映され、 and を使用するクラスごとに 2 つの異なるバージョンを作成する必要がFoo1ありFoo2ます (たとえば、 and を作成する必要がFooContainer1ありますFooContainer2)。

これを行うより邪魔にならない方法は、作成することです

class Bar: public Foo, public Decorator1, public Decorator2
{   }

の代わりにこれを使用しますFoo。この場合、必要な関数だけを呼び出して、他の関数はDecorator1無視Decorator2しますが、これは優れた OOP 手法に反するようです。

問題に関する提案はありますか?

4

4 に答える 4

8

このような単純なポリモーフィズムを使用してみませんか?

class Foo
{
public:
    Foo()  {   }
    virtual ~Foo() {   }
    float member1() { return _member1; }
private: 
    float _member1;
    // other members etc...
}

class Foo1 : public Foo
{   
    public:
   int   alpha() { return _alpha; }
   float beta()  { return _beta; }
private:
   int _alpha;
   float _beta;
}

class Foo2 : public Foo
{   
    typedef std::complex<float> cmplx;
public:
   cmplx  gamma() { return _gamma; }
   double delta()  { return _delta; }
private:
   cmplx  _gamma;
   double _delta;
}

class FooContainer
{
public:
   FooContainer() {   }
   ~FooContainer() {   }
   void addFoo(Foo* f) {_foos.push_back(f);}
private:
   boost::ptr_vector<Foo> _foos;
}

その後、クライアント コードを変更する必要はありません。GUI コマンドに従って、Foo1 または Foo2 を作成し、単一のコンテナーに追加できます。必要に応じて、Foo ポインターの dynamic_cast を使用して、Foo1 または Foo2 にキャストできます。ただし、クライアント コードを適切に記述していれば、これは必要ありません。

于 2012-07-06T13:51:14.713 に答える
0

ポリシーベースのテンプレートはどうですか? クラスをテンプレート パラメーターとして受け取るテンプレート クラス Foo を用意します。次に、デコレータ メソッドを呼び出す 2 つのメソッドを用意します。

tempate <class Decor>
class Foo
{
public:
    Foo() : { __d = Decor()  }
    ~Foo() {   }
    float member1() { return _member1; }
    Decor::method1type decoratorMember1() { return __d.getValueMethod1();}
    Decor::method2type decoratorMember2() { return __d.getValueMethod2();}
private: 
    float _member1;
    Decor __d;
    // other members etc...
}

次に、複雑なデコレーターで次のようにします。

class Decor1 {
  typedef std::complex<float> method1type;
  typedef double method2type;
public:
  method1type getValueMethod1() {return _gamma}
  method2type getValueMethod2() {return _delta}
private:
  method1type _gamma;
  method2type _delta;
}

もう一方も同じです。このようにして、Fooコードが既にコンパイルされている場合でも、コードに何でも追加できます。宣言子クラスを作成するだけです。をインスタンス化する代わりに、次のようにFoo1します。

Foo<Decor1> f;
于 2012-07-06T14:01:54.070 に答える
0

mixinタイプの機能を処理しようとしているようです。そのために、テンプレートを使用できます。これは、各クラスのコピーが生成されるという意味では実行時ではありませんが、入力の手間が省けます。

したがって、デコレーターごとに、次のようにします。

template<class TBase> class Decorator1 : public TBase
{
public:
    void NewMethod();
}

次に、たとえば次のことができます。

Foo* d = new Decorator1<Foo1>(...);

もちろん、これを実行時に機能させる唯一の方法は、作成するタイプを決定することです。ただし、最終的には typeFooになるため、必要に応じてそれらの間でキャストしたり、RTTI を使用しFoo1たりDecorator1できます。

詳細については、この記事このドキュメントを参照してください。


私はそれを潜在的な解決策として提案しましたが、個人的には可能な限りポリモーフィズムの提案を採用したいと思います.ミックスインを使用して配置します。ほんの 2 セントです。うまくいくと思われる場合は、ぜひお試しください。

于 2012-07-06T14:05:59.803 に答える
0

クラスの基本的な概念は、カプセル化されているため、定義後にメンバーを追加できないということです (ポリモーフィズムを使用して、追加のメンバーを持つ派生クラスを作成することはできますが、元のクラスのポインターを介して呼び出すことはできません: キャストする必要があります)。これは危険です)、特に実行時ではありません。

したがって、要件がオブジェクト指向プログラミングの本質的な考え方を壊しているように思えます。これは、非メンバー関数を使用するという簡単な解決策を示唆しています。それらはいつでも定義でき、実行時でも定義できます (コンパイルする必要がある場合)。関数ポインターのオーバーヘッドは以前と同じです (新しいメンバー関数へのポインターが必要な場合)。

于 2012-07-06T14:16:42.087 に答える