2009-04-08 14 views
4

実行時にオブジェクトの動作を変更する方法はありますか? (C++を使用)実行時にオブジェクトの動作を変更する

私は簡単な例を示します。私は方法operateを含むクラスOperatorを持っています。

double operate(double a, double b){ 
    return 0.0; 
} 

ユーザーがabのためのいくつかの入力値を与えるであろう、との彼は加算や乗算を計算するために選択することができることを言わせて実行するためにどのような操作を選択します:それはこのようになりますとしましょう。入力が与えられているとすれば、Operatorをインスタンス化し、operate(a, b)と呼びます。これは前に述べたとおりに書かれています。

乗算や加算を計算するメソッドは、どこかに実装されます(どこにもわかりません)。

結論私は、ユーザーの入力に応じて、私のオペレータオブジェクトの動作を変更する必要があります。

+1

あなたは何をしようとしているのですか?たぶんあなたは多型について考えるべきです。 –

+0

何が必要ですか?質問を展開してください。 – bayda

+0

質問を展開する必要があります。特定の状況下で行うことができるものよりもいくつかあります... –

答えて

1

オブジェクトには、常にそのクラスによって定義された動作があります。

あなたは異なる動作が必要な場合は、別のクラスが必要...

0

多く、このプロキシを行う方法、PIMPLイディオム、多型、長所と短所を持つすべてがあります。あなたに最も適したソリューションは、あなたが解決しようとしている問題の正確さに依存します。

2

動的バインディング(多態性)によって実現できますが、実際に達成しようとしているものによって異なります。

0

多くの多くの方法:

は、最初はifを試してみてください。 if文でいつでも振る舞いを変更することができます。そして、おそらく多形性の方がより正確ですが、それはあなたの仕事に依存します。

9

このための標準的なパターンは、外部クラスに "実装"クラスへのポインタを持たせることです。 impl_メンバーにSwitcherooのすべてのメンバ関数を転送することによって

// derive multiple implementations from this: 
class Implementation 
{ 
    virtual ~Implementation() {} // probably essential! 

    virtual void foo() = 0; 
}; 

class Switcheroo 
{ 
    Implementation *impl_; 

public: 
    // constructor, destructor, copy constructor, assignment 
    // must all be properly defined (any that you can't define, 
    // make private) 

    void foo() 
    { 
     impl_->foo(); 
    } 
}; 

、あなたがする必要がある場合は、必ず別の実装に切り替える機能を取得します。

このパターンにはさまざまな名前があります:Pimpl(「private implementation」の略)、Smart Reference(スマートポインターとは対照的に、fowardingメンバー機能によるもの)であり、ProxyおよびBridgeと共通していますパターン。

2

オブジェクトが何らかの手法(構図、コールバックなど)で 'プラグイン'動作を使用することを意図していない限り、任意のオブジェクトの動作を変更することはできません。

(非常識な方法は、機能コードがあるプロセスメモリを上書きされる可能性があります...)

ただし、実行可能ファイルにメモリを上書きせずにvtableのを上書きすることにより、仮想メソッドであり、オブジェクトの振る舞い(An approach can be found in this article)を上書きすることができますページ。しかし、これはまだそれを行うには非常に穏やかな方法ではなく、複数のセキュリティリスクがあります。

最も安全なことは、適切なフック(コールバック、合成など)を提供することによって変更されるように設計されたオブジェクトの動作を変更することです。

6

私は

WARNING危険...のみトリビアとしてこれを言及することだし、もっとそれをunrecommendすることはできませんが、ここで私達は行きます! 愚かな私が見たトリックは、と思うが、それは本当に愚かなのです。基本的には、別のクラスのポインタに仮想テーブルのポインタを入れ替えると、理論的には世界が破壊されたり、他の未定義の動作が発生する可能性があります:

とにかく動的クラスとコーシャーC++を使用しますが、上記は楽しいものです...

+0

おもしろいと思う...試してみてください:) – Shree

+0

あなたのdownvoteと一緒にコメントを残してくれてありがとう@Anon :) –

0

抽象クラスを作成し、動作を変数として仮想として宣言します。 仮想メソッドを実装する具象クラスを作成します。これを達成するには、デザインパターンを使用する方法がたくさんあります。

0

dynamic bindingを使用してオブジェクトの動作を変更できます。 Decorator,Strategyのようなデザインパターンは、実際に同じことを実現するのに役立ちます。

3

Coplienの封筒/レターパターンは、(彼のブック高度なC++プログラミングスタイルとイディオムを読まなければならない)、これを行うための古典的な方法です。

簡単に言うと、エンベロープとレターは、すべてのサブクラスのパブリックインターフェイスを定義する抽象基本クラス/インターフェイスのサブクラスです。

封筒は、文字を保持しています(真のタイプを隠しています)。

さまざまなレタークラスには、抽象クラスのパブリックインターフェイスの実装が異なります。

エンベロープには実際の実装はありません。その手紙のほんの一部(代表者)です。これは、抽象基本クラスへのポインタを保持し、それを具体的なレタークラスインスタンスでポイントします。インプリメンテーションを変更する必要があるので、toへのLetterサブクラスのポインタのタイプが変更されます。

ユーザーはエンベロープへの参照のみがあるため、エンベロープの動作が変更される点を除いて、この変更は表示されません。

Coplienの例は、文字のためであり、変更を引き起こすエンベロープではないため、特にきれいです。

1つの例は、Numberクラス階層です。抽象的なベースは、すべての数値に対するある種の演算、例えば加算を宣言します。 IntegerとComplexは具体的なサブクラスの例です。

IntegerとIntegerを追加するとIntegerが生成されますが、IntergetとComplexを追加するとComplexになります。

はここで封筒を追加するための次のようになります。クライアントのポインタで今

public class Number { 
    Number* add(const Number* const n) ; // abstract, deriveds override 
} 

public class Envelope : public Number { 
    private Number* letter; 

... 

    Number* add(const Number& rhs) { // add a number to this 
    // if letter and rhs are both Integers, letter->add returns an Integer 
    // if letter is a a Complex, or rhs is, what comes back is a Complex 
    // 
    letter = letter->add(rhs)) ; 
    return this; 
    } 
} 

変化したことがない、と彼らはこれまでにエンベロープを保持しているかを知る必要がありません。ここでは、クライアントコードです:彼の本で

int main() { 
    // makeInteger news up the Envelope, and returns a pointer to it 
    Number* i = makeInteger(1) ; 
    // makeComplex is similar, both return Envelopes. 
    Number* c = makeComplex(1, 1) ; 

    // add c to i 
    i->add(c) ; 


    // to this code, i is now, for all intents and purposes, a Complex! 
    // even though i still points to the same Envelope, because 
    // the envelope internally points to a Complex. 
} 

は、Coplienはより深くに入る - 、及び糖衣構文を追加します - あなたは、addメソッドは、何らかの形のマルチ派遣を必要とすることに注意しましょう。しかし、これはの要点で、「ランタイムポリモーフィズム」と呼ばれるものをどのように得ることができます。

1

また...ダイナミックbinding..i'mあなたはStrategyパターンが、1つはまた、良い解決策のように聞こえる役割について読んdo..I同じことに苦しんでRole Patternを検討することもでき

関連する問題