2011-02-06 27 views
5

方法はありますか?2つの同様の関数セット(C/C++)を効果的に切り替えることはできますか?C++で2つの関数セットを切り替える方法は?

void a_someCoolFunction(); 
void a_anotherCoolFunction(int withParameters); 
… 

void b_someCoolFunction(); 
void b_anotherCoolFunction(int withParameters); 
… 

そして、私が使用されている1実行時に私のプログラムでは、「スイッチ」することにしたい: は私が何を意味するか良く説明するために、私のようなグローバル関数の2セットを持って言うことができます。しかし:私は1つを持っているしたいいけない場合などの条件ですべての機能、:

void inline someCoolFunction(){ 
    if(someState = A_STATE){ 
     a_someCoolFunction(); 
    }else{ 
     b_someCoolFunction(); 
    } 
} 

私はすべての機能が私のメインループで多く呼び出されることを期待し、そのため - 私は何かをすることができればそれが望ましいだろうこのような(私のメインループの開始時またはsomeStateが変更されたとき):その後、

if(someState = A_STATE){ 
    useFunctionsOfType = a; 
}else{ 
    useFunctionsOfType = b; 
} 

と単に

useFunctionsOfType _someCoolFunction(); 

が、私はその理解できるのを願って呼び出します私の背景:私はOpenGL ES 1.1とOpenGL ES 2.0を両方とも正しく処理できるはずのアプリケーションを書いていますが、すべてのレンダリングメソッドを2回書く必要はありません(例:renderOpenGL1()renderOpenGL2())のみrender())。私はすでに類似したメソッドを持っています:glLoadIdentity(); myLoadIdentity(); ...しかし、これらの2つを何とか切り替える方法が必要です。 効果的な方法でこれを達成する方法はありますか? (これらに限定されない)を含む

+0

関数ポインタのようなサウンドは、このトリックを行う必要があります。 – gablin

+7

注:このようにCとC++を混同しないでください。潜在的な解決方法は、使用している言語によって大きく異なります。それを選んでください! –

+0

すべての関数が 'alot'と呼ばれている場合は、' alot() '内のディスパッチャを変更するだけです。ところで、この「たくさん」はかなり毛深い獣でなければなりません! http://hyperboleandahalf.blogspot.com/2010/04/alot-is-better-than-you-at-everything.html – Potatoswatter

答えて

2

(CとC++の両方が必要なので)これは関数へのポインタで行われます。

これらの関数をグループに入れ替えて、関数へのポインタの配列を設定し、その配列を渡すことをお勧めします。あなたがそうすることを決定した場合、あなたはおそらくも読み容易にするために、いくつかのマクロを定義する場合があります

void (*functions_a[2])(); 
    void (*functions_b[2])(); 

    void (**functions)() = functions_a; 

    .... 
    #define theCoolFunction()  functions[0]() 
    #define theOtherCoolFunction(x) functions[1](x) 
    .... 

    // switch grooup: 
    functions = functions_b; 

をが、この場合には、あなたは、引数の型の静的チェックを失うことになる(そして、あなたは配列を初期化する必要があります、 もちろん)。私はCに推測

++あなたがそのメソッドのために同じ親クラスと異なる実装を持つinstatiate 2つの異なるオブジェクトを持つことになります(ただし、私はC++ prograammerよん!)Cでは

8

いくつかのオプション、:

  • 使用関数ポインタ。
  • これらをクラスで囲み、多型を使用します。
  • 2つのループのコピーがあります。これを確実に

しかしくださいプロファイルは、あなたのコードへの大きな変更を加える前実際問題です。

+0

あなたが大規模な変更を行う前にプロフィールを+1してください:) – neuro

1

単純な方法は、関数へのポインタを格納し、要求を変更することができます。

しかし、より良い方法は、abstract factoryデザインパターンに類似したものを使用することです。素晴らしい汎用実装はLoki libraryにあります。

2

関数ポインタを使用できます。もしあなたがgoogleに興味があれば、たくさんのことを読むことができますが、簡単に言えば、関数ポインタは関数のメモリアドレスへのポインタを格納しています。

ファンクションポインタはファンクションと同じ方法で使用できますが、さまざまな機能のアドレスを割り当てることができ、何らかの "ダイナミック"な機能にします。例:

typedef int (*func_t)(int); 


int divide(int x) { 
    return x/2; 
} 

int multiply(int x) { 
    return x * 2; 
} 

int main() { 
    func_t f = ÷ 
    f(2); //returns 1 
    f = &multiply; 
    f(2); //returns 4 
} 
1

をあなたはstructでこれを行う一般的でしょう関数ポインタ含む:アクティブ関数テーブルを切り替えるには

struct functiontable { 
    void (*someCoolFunction)(void); 
    void (*anotherCoolFunction)(int); 
}; 

const struct functiontable table_a = { &a_someCoolFunction, &a_anotherCoolFunction }; 
const struct functiontable table_b = { &b_someCoolFunction, &b_anotherCoolFunction }; 

const struct functiontable *ftable = NULL; 

を、あなたが使用したい:

ftable = &table_a; 

をトンを呼び出すには彼は機能します:

ftable->someCoolFunction(); 
2

boost :: function(std :: function)のようなものが請求書に適合します。あなたの例を使用する:G ++でコンパイル

#include <iostream> 
#include <boost/function.hpp> //requires boost installation 
#include <functional> //c++0x header 


void a_coolFunction() { 

    std::cout << "Calling a_coolFunction()" << std::endl; 
} 

void a_coolFunction(int param) { 

    std::cout << "Calling a_coolFunction(" << param << ")" << std::endl; 
} 

void b_coolFunction() { 

    std::cout << "Calling b_coolFunction()" << std::endl; 
} 

void b_coolFunction(int param) { 

    std::cout << "Calling b_coolFunction(" << param << ")" << std::endl; 
} 
float mul_ints(int x, int y) {return ((float)x)*y;} 


int main() { 

    std::function<void()> f1; //included in c++0x 
    boost::function<void(int)> f2; //boost, works with current c++ 
    boost::function<float(int,int)> f3; 

    //casts are necessary to resolve overloaded functions 
    //otherwise you don't need them 
    f1 = static_cast<void(*)()>(a_coolFunction); 
    f2 = static_cast<void(*)(int)>(a_coolFunction); 

    f1(); 
    f2(5); 

    //switching 
    f1 = static_cast<void(*)()>(b_coolFunction); 
    f2 = static_cast<void(*)(int)>(b_coolFunction); 

    f1(); 
    f2(7); 

    //example from boost::function documentation. No cast required. 
    f3 = mul_ints; 
    std::cout << f3(5,3) << std::endl; 

} 

- 4.4.4、この出力:

Calling a_coolFunction() 
Calling a_coolFunction(5) 
Calling b_coolFunction() 
Calling b_coolFunction(7) 
15 

最大の制限は、f1の種類、F2、などが変更できないということですので、あなたが割り当てた任意の関数それらには同じ署名(すなわち、f2の場合はvoid(int))を持たなければなりません。

4

質問はC++ソリューションに興味があるようで、誰も多型ソリューション(あまりにも明白ですか?)を綴っているわけではありません。

必要なAPIを持つ抽象基本クラスを定義し、各サポートの実装のための派生クラスを実装します。これはまさにC++が意図された事の一種である、そうであればということ

class OpenGLAbstract 
{ 
    public: 
     virtual ~OpenGLAbstract() {} 
     virtual void loadIdentity() = 0; 
     virtual void someFunction() = 0; 
}; 

class OpenGLEs11 : public OpenGLAbstract 
{ 
    public: 
     virtual void loadIdentity() 
     { 
      // Call 1.1 API 

     } 
     virtual void someFunction() 
     { 
      // Call 1.1 API 
     } 
}; 


class OpenGLEs20 : public OpenGLAbstract 
{ 
    public: 
     virtual void loadIdentity() 
     { 
      // Call 2.0 API 
     } 
     virtual void someFunction() 
     { 
      // Call 2.0 API 
     } 
}; 

int main() 
{ 
    // Select the API to use: 
    bool want11 = true; 
    OpenGLAbstract* gl = 0; 
    if (want11) 
     gl = new OpenGLEs11; 
    else 
     gl = new OpenGLEs20; 

    // In the main loop. 
    gl->loadIdentity(); 

    delete gl; 
} 

注意をここでC++を使うことができますが、これは最も簡単な方法です。

あなたの2.0バージョンでは、実行時に2.0プラットフォームの実装でダイナミックリンクライブラリをロードするプロセスが必要な場合、より微妙な問題が発生する可能性があります。その場合、APIスイッチをサポートするだけでは(ソリューションが何であれ)十分ではありません。代わりに、独自のリンクライブラリ内の各OpenGLの具象クラスを入れて、それぞれにそのクラスを作成するファクトリ関数を提供します。

OpenGlAbstract* create(); 

その後、実行時に必要なライブラリをロードしてAPIにアクセスするためのcreate()メソッドを呼び出します。

+1

+1、私は人々が機能するためのポインタと長い間機能するポインタの配列にとどまるかどうか疑問に思っていました。 –

関連する問題