2011-02-02 95 views
4

我已经找到了这个,但我想我只是让自己更困惑。是否可以将一个函数(指针?)保存到一个对象中?

我想要做的事情是保存一个对象中的函数指针,并让它在稍后的另一个线程中被调用。

我一直在想象的是一个构造函数,它会带一个函数指针和传递给这个函数指针的参数。这个对象还有一个run()方法,它将运行所述的函数指针和一个wait_until_completed()方法,这个方法将阻塞直到函数运行完毕。

函数指针应该是来自另一个对象的函数,如果这是有道理的。例如

Foo::*Bar(int); 

我有wait_until_completed()使用pthread_cond_t的工作,但我坚持这个函数指针的东西,感觉就像我只是手忙脚乱。

有什么建议吗?

编辑:这是学校(我的任何一般的理解),这样的第三方库不会工作:/

我觉得我做了一个非常差的工作,解释这一点,让我给一些示例代码(不包括所有同步的东西)

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); 

现在你可以使用类型定义是这样的:

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; 
} 

这可能是有点多,在一次消化,但我希望这可以帮助你理解的成员函数指针,以及如何使用它们。 :)

3

这听起来像你试图重新发明“命令”模式。 Loki(其中许多人)应该给出一个合理的开始(尽管你可能必须自己添加线程同步)。

+0

仅供参考:关于[命令模式](http://en.wikipedia.org/wiki/Command_pattern)的一般维基百科,以及[C++特定论述](http://www.dreamincode.net /论坛/主题/ 38412-的命令图案C /)。 – 2011-02-02 22:01:16

+0

我不怀疑洛基会更好,但是这是一个学校任务,主要是我只是想弄清楚这是如何工作:(感谢信息,但我会保持洛基在脑海中,当我做任何我的个人项目! – vimalloc 2011-02-02 22:12:35

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一概而论,和参数binder,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::async获得std::future;你可以编写一个线程池或其他一些异步完成任务的工具,让其中一个生成并返回期货。

1

有关您的示例代码的所有内容在技术上都是正确的,并且应该可以正常工作,但尝试将NULL分配给声明的成员变量时除外。这只能用静态积分完成,而函数指针不计数。

所以,删除该行,你的例子应该工作得很好,从我可以告诉。

这样说,你应该更喜欢初始化器在构造函数体中的赋值。它应该看起来像这样:

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

编辑:哦,我错过了你的OP中的东西。在上面,您正在接受指向成员函数作为您的参数,但试图将其称为正常函数。更正后的格式将使用void (*)(int)作为您的类型而不是void (Bar::*)(int)

+0

我得到的错误是抱怨Bar :: * fun - “expected”)''''之前'::'token。PS感谢关于NULL的信息:) – vimalloc 2011-02-02 22:50:12

相关问题