2011-02-02 11 views
4

私はこれを検索しましたが、私は自分自身をもっと混乱させていると思います。関数(ポインタ?)をオブジェクトに保存することはできますか?

私がやろうとしているのは、オブジェクトに関数ポインタを保存し、後で別のスレッドで呼び出すようにすることです。

私が想像したことは、関数ポインタとこの関数ポインタに渡されるパラメータをとるコンストラクタです。このオブジェクトには、前記関数ポインタを実行するrun()メソッドと、関数が実行されるまでブロックするwait_until_completed()メソッドもあります。

関数ポインタは、意味があれば別のオブジェクトからの関数になるはずです。例

Foo::*Bar(int); 

のために私が持っているwait_until_completed()pthread_cond_tを使用して作業していて、この関数ポインタのものに貼り付けて、私はちょうどサークルで走り回っていますように感じるのです。

アドバイスはありますか?

EDITは:/

私は非常に悪い仕事は、私はいくつかのサンプルコードを提供できるように、このことを説明しましたように私は感じた(すべて除く:これは、作業習慣学校(任意の私の一般的な理解)ので、サードパーティのライブラリのためであります

class Foo 
{ 
public: 
    Foo(void (Bar::*function) (int), int function_param) 
    { 
     // Save the function pointer into this object 
     this->function = &function; 

     // Save the paramater to be passed to the function pointer in this object 
     param = function_param; 
    } 

    run() 
    { 
     (*function)(param); 
    } 

private: 
    // The function pointer 
    void (Bar::*function) (int) = NULL; 

    // The paramater to pass the function pointer 
    int param; 
} 

これは一言で言えば、私がやろうとしていることです。しかし、それが文法か私がばかげているかどうかは分かりませんが、実際にこれを行い、コンパイルする方法を理解することはできません。

しかし、これまでのすべてのアドバイスに感謝します:)

答えて

8

最初に、機能タイプをtypedefにすると、再利用しやすくなり、間違いの可能性を減らすことができます。

typedef void (Bar::*function_type)(int); 

今、あなたはこのようにtypedefをを使用することができます。

Foo(function_type func, int func_param) 
    : function_(func) 
    , param_(func_param) 
{ 
} 

はまた、それは(あなたが初期化リストhereについての詳細を見つけることができます)メンバ変数を初期化する初期化リストを使用することをお勧めします。
ただし、依然としてこの関数を呼び出すことはできません。 とも呼ばれるクラスメンバ関数は、がバインドされたであるため、インスタンス化されたオブジェクトで使用する必要があります。あなたのrun関数は(あなたはまた、戻り値の型を忘れてしまった)このように見えるしなければなりません:

void run(Bar* object){ 
    (object->*function_(param_)); 
} 

それは、メンバ関数ポインタを経由してメンバ関数を呼び出すために、特別な->*演算子を使用しています。
また、ほとんどの変数をクラス内で直接初期化することはできません(static const int i = 5;のような静的積分定数のみ)。 Fooオブジェクトをインスタンス化し、その上で実行関数を呼び出すことができます。
が ここでは、完全にコンパイル可能例を得た:

#include <iostream> 
using namespace std; 

class Bar{ 
public: 
    void MyBarFunction(int i){ 
     cout << i << endl; 
    } 
}; 

class Foo 
{ 
public: 
    typedef void (Bar::*function_type)(int); 

    Foo(Bar* object, function_type function, int function_param) 
     : object_(object) // save the object on which to call the function later on 
     , function_(function) // save the function pointer 
     , param_(function_param) // save the parameter passed at the function 
    { 
    } 


    void Run() 
    { 
     (object_->*function_)(param_); 
    } 

private: 
    // The object to call the function on 
    Bar* object_; 

    // The function pointer 
    function_type function_; 

    // The paramater to pass the function pointer 
    int param_; 
}; 

int main(void){ 
    // create a Bar object 
    Bar bar; 
    // create a Foo object, passing the Bar object 
    // and the Bar::myBarFunction as a parameter 
    Foo foo(&bar, &Bar::MyBarFunction, 5); 

    // call Bar::MyBarFunction on the previously passed Bar object 'bar' 
    foo.Run(); 

    cin.get(); 
    return 0; 
} 

これは、一度に消化する少しくらいかもしれないが、私は、これはあなたがメンバ関数ポインタを理解し、それらをどのように使用するのに役立ちます願っています。 :)

+0

これは正確に私が探していたものですコードを見ても多くの助けになります!ありがとう:) – vimalloc

3

「コマンド」パターンを再発明しようとしているようです。 Loki(他の多くの人の間で)合理的なスタートを与えるべきです(スレッド同期を自分で追加する必要があります)。

+0

参考:一般的な[コマンドパターン](http://en.wikipedia.org/wiki/Command_pattern)と[C++固有の論文]のWikipedia(http://www.dreamincode.net/forums/topic/38412-the-command-pattern-c /)を参照してください。 –

+0

私はlokiがより良いとは思わないが、これは学校の割り当てのためであり、主に私はこれがどのように動作するか把握しようとしている:(しかし、情報のおかげで、私はlokiを心配しています私の個人的なプロジェクト! – vimalloc

2

boost functionオブジェクトを使用してください。

編集:ここに簡単な例です:

#include <iostream> 
#include <boost/function.hpp> 

struct X { 
    int foo(int a, int b) { return a * b; } 
}; 

int main(void) 
{ 
    boost::function<int (X*, int, int)> func; 
    func = &X::foo; 

    X x; 
    std::cout << func(&x, 1, 2) <<std::endl; 

    return 0; 
} 
4

はい、あなたは関数ポインタを格納することができます:

struct simple_callable_object 
{ 
    void (*f_)(); 
    simple_callable_object(void (*f)()) : f_(f) { } 

    void operator()() { f_(); } 
}; 

このパターンは多様関数のラッパー、function、および引数に一般化されますバインダー、bindは、Boost、C++ TR1、およびC++ 0xにあります。

関数を非同期で実行し、後でそれをブロックして完了するまで待機するパターンは、「未来」と呼ばれます。このタスクを容易にするC++ 0xスレッドサポートライブラリにはstd::futurestd::asyncがあります。たとえば:

// pretend 'f' is a long-running task that you want to run asynchronously: 
int f(int x) { return x * 2; } 

void g() 
{ 
    std::future<int> fi = std::async(f, 21); 

    // do other meaningful work 

    int x = fi.get(); // blocks until the async task completes 
} 

あなたはstd::futureを取得するためにstd::asyncを使用する必要はありません。非同期的にタスクを完了し、そのうちの1つが未来を生成して返すスレッドプールまたはその他の機能を書くことができます。

1

あなたのサンプルコードに関するすべては、技術的に正しいので、宣言されているメンバ変数にNULLを代入しようとする試みを除いて、動作するはずです。これは静的積分でのみ行うことができ、関数ポインタはカウントしません。

だから、その行を削除すれば、あなたの例はわかります。

これで、コンストラクタ本体に代入するためにイニシャライザを使用することをお勧めします。あなたのように見えるはずです。

Foo(void (Bar::*fun) (int), int fparam) : function(fun), param(fparam) {} 

編集:うわー、私はあなたの仕事で何かを見逃しました。上記のメンバーへのポインターをパラメーターとして受け取りますが、それを通常の関数として呼び出そうとしています。修正された形式はvoid (Bar::*)(int)ではなく、void (*)(int)をあなたのタイプとして使用することになります。

+0

私が得ているエラーは、Bar :: * fun - "expected"の前に '::'トークンに苦しんでいます。PSはNULLについての情報をありがとうございます:) – vimalloc

関連する問題