2015-12-21 85 views
0

我试图在下面的代码,但该程序崩溃的工作:将回调函数传递给std :: map的最佳方式是什么?

#include <iostream> 
#include <string> 
#include <map> 

using namespace std; 

typedef void (*callBackMethod)(string); 
class CTest 
{ 
private: 
    map<string, callBackMethod> mapMethod; 

    void testMethod(string msg) 
    { 
     cout << msg << endl; 
    } 
public: 
    CTest() 
    { 
     addFunction("AA", (callBackMethod) &CTest::testMethod); 
    } 
    void addFunction(string funName, callBackMethod methodName) 
    { 
     mapMethod[funName] = methodName; 
    } 
    callBackMethod getMethod(string funName) 
    { 
     auto fun = mapMethod.find(funName); 
     if(fun == mapMethod.end()) { return nullptr; } 
     return fun->second; 
    } 
    void runFunction(string funName) 
    { 
     getMethod(funName)("test"); 
    } 

}; 

int main() 
{ 
    CTest test; 
    test.runFunction("AA"); 

    return 0; 
} 

我有,我需要私有方法传递到地图的要求。该程序编译时出现警告:

converting from 'void (CTest::*)(std::__cxx11::string) {aka void (CTest::*)(std::__cxx11::basic_string<char>)}' to 'callBackMethod {aka void (*)(std::__cxx11::basic_string<char>)}' 

当我执行此操作时,它崩溃。

当我将回调方法移出它的工作类之外。我的要求是让程序流动(隐藏需要添加到地图的外部呼叫的方法)。

期待您的意见。

+1

为什么地球上你会认为将一个指向成员函数的指针指向函数是个好主意? –

+0

@ T.C。那你有什么建议?如果你愿意,请修改代码。 – programmer

+0

[如何将非静态成员函数作为回调函数传递?](http://stackoverflow.com/questions/2097738/how-to-pass-a-non-static-member-function-as- a-callback) –

回答

0

如果您需要指向CTest成员函数和自由函数,然后您可以使用std::function<void(std::string)>

#include <iostream> 
#include <string> 
#include <map> 
#include <functional> 

using namespace std; 

using callBackFunction = std::function<void(string)>; 

void testFunction(string msg) 
{ 
    cout << "[" << __PRETTY_FUNCTION__ << "] " << msg << endl; 
} 

class CTest 
{ 
private: 
    map<string, callBackFunction> mapMethod; 

    void testMethod(string msg) 
    { 
     cout << "[" << __PRETTY_FUNCTION__ << "] " << msg << endl; 
    } 
public: 
    CTest() 
    { 
     addFreeFunction("AA", testFunction); 
     addMemberFunction("BB", &CTest::testMethod); 
    } 
    void addMemberFunction(string funName, void(CTest::*methodName)(string)) 
    { 
     using std::placeholders::_1; 
     mapMethod[funName] = std::bind(methodName, this, _1); 
    } 
    void addFreeFunction(string funName, void(*methodName)(string)) 
    { 
     mapMethod[funName] = methodName; 
    } 
    callBackFunction getMethod(string funName) 
    { 
     auto fun = mapMethod.find(funName); 
     if(fun == mapMethod.end()) { return nullptr; } 
     return fun->second; 
    } 
    void runFunction(string funName) 
    { 
     getMethod(funName)("test"); 
    } 

}; 

int main() 
{ 
    CTest test; 
    test.runFunction("AA"); 
    test.runFunction("BB"); 

    return 0; 
} 

注意CTest必须根据要传递什么类型的功能,因为对于成员函数必须提供,这就是它在此被调用,this对象元素插入所述地图以不同的方式例。这通过使用std::bind来实现。

+0

谢谢。你的代码工作。但是现在隐藏了回调方法签名。我还需要从main传递回调方法。例如:void tst2(string s){cout <<“New”<< s;} ....以及main(){... test.addFunction(“BB”,&tst2); ...}编译错误。有没有更好的方法来处理这种情况。非常感谢。 – programmer

+0

所以你需要使用成员和非成员函数? –

+0

是的。我需要使用成员函数和非成员函数。 – programmer

0

既然你想使用成员变量,你需要在你的typedef指定不同的签名:

在C++ Builder中的下面可以做:

typedef void(__closure *callBackMethod)(string); 

如果你这样做,我不建议您保留一个智能指针指向该成员所属的对象,以便您可以在调用该函数之前检查该对象是否仍然有效,否则将导致该应用程序崩溃。

__closure关键字是C++ Builder的扩展来解决要求使用完全合格的成员名称source

为了应对全球和成员函数,我们有以下几点:

typedef void(__closure *callBackMethodMember)(string); 
typedef void (*callBackMethodGlobal)(string); 

/* And then on 2 overloaded functions */ 
void addFunction(string funName, callBackMethodMember methodName) {} 
void addFunction(string funName, callBackMethodGlobal methodName) {} 
+0

'__closure'是什么意思?它是标准的C++吗? –

+0

我看到'__closure'是C++的C++ Builder扩展。所以如果你不使用C++ Builder,它将不可用。 [文档](http://docwiki.embarcadero.com/RADStudio/XE8/en/C%2B%2B_Keyword_Extensions#closure) –

+0

但它有什么作用?可能有一个标准的等值。 –

相关问题