【发布时间】:2014-10-03 14:34:08
【问题描述】:
我试图在 boost 的帮助下像普通 C 函数一样调用类成员函数,但是我的 efforts into looking how to 只是失败了,所以我想出了我自己的东西,听起来很直观的东西......我想。
但问题是,当调用指向 boost::function - fooA 和 fooB 的指针时,它只会不断崩溃。
对其进行一些测试:
#include <boost/bind.hpp>
#include <boost/function.hpp>
class MyOtherClass{
public:
MyOtherClass(){}
};
class MyClass
{
std::string name;
public:
void MyFunction(MyOtherClass *data)
{
std::cout << "NAME:" << name << std::endl;
}
boost::function<void(MyOtherClass *)> bindMyFunction;
MyClass(std::string _name)
: name(_name)
{
bindMyFunction = std::bind1st(std::mem_fun(&MyClass::MyFunction), this);
}
};
然后我在 main 中只执行一次代码来尝试它,我希望看到 NAME:a\nNAME:b\n 三次,但两次后它就崩溃了:
int main()
{
MyClass a("a");
MyClass b("b");
MyOtherClass c;
//make sure we can save the Class::bindMyFunction variable
void ** someTestA = (void**)&a.bindMyFunction;
void ** someTestB = (void**)&b.bindMyFunction;
//'convert' it to the needed type, just like function-pointers work
//The library uses this below
// Now the correct assignment is the hard part
void(*fooA)(MyOtherClass*) = (void(*)(MyOtherClass*))(*someTestA);
void(*fooB)(MyOtherClass*) = (void(*)(MyOtherClass*))(*someTestB);
//Works
a.MyFunction(&c);
b.MyFunction(&c);
//Works
a.bindMyFunction(&c);
b.bindMyFunction(&c);
//execute the boost::function by calling it like a function
//Crash
fooA(&c);
fooB(&c);
return 0;
}
不幸的是,我使用了一个只接受参数void(*)(MyOtherClass*) 的库,但我需要将它封装在一个类中。该库使用回调来通知任何更改。所以我需要想办法将boost::function<void(*)(MyOtherClass*)> 转换为void(*)(MyOtherClass*) 类型,然后让库能够call(parameters) 它。
但这似乎是一项很难完成的任务。有什么方法可以正确地做到这一点吗?
编辑:根据要求,我会让这个问题更具体,但我担心这个问题会以这种方式过于本地化,但在这里:
我正在尝试创建一个封装了 RakNet 的类。将所有内容都放入类中(甚至是 RakNet 回调)。该类的每个对象实例都是一个自己的客户端,它将连接到游戏服务器:
class MyClass
{
RakClientInterface* pRakClient;
void MyFunction(RPCParameters *pParams){}
boost::function<void(RPCParameters *)> bindMyFunction;
public:
MyClass()
{
pRakClient = RakNetworkFactory::GetRakClientInterface();
if (pRakClient == NULL)
return;
bindMyFunction = std::bind1st(std::mem_fun(&MyClass::MyFunction), this);
//void RakClient::RegisterAsRemoteProcedureCall( int* uniqueID, void ( *functionPointer ) ( RPCParameters *rpcParms ) )
pRakClient->RegisterAsRemoteProcedureCall(&RPC_ServerJoin, /*<need to pass boost::function here somehow>*/);
}
};
【问题讨论】:
-
您的代码首先获取
boost::function的对象表示的4 个字节,然后告诉编译器这是一个普通函数指针。因此,您的代码依赖于编译器。您的程序表现出未定义的行为。 -
好吧,我希望它能起作用,我真的很拼命地寻找一种能够以某种方式执行
boost::function<T>(params)的方法,方法是使用来自void(*fooA)(MyOtherClass*)变量的数据并将其称为fooA(params)。 -
顺便说一句,您可以将不捕获任何内容的 lambda 静态转换为函数指针。
static_cast<DoItRet (*)(MyOtherClass*)>( [](MyOtherClass* p){return ((ActualClass*)p)->DoIt();} ); -
您使用的库看起来设计得很糟糕。它根本不会将任何上下文信息传递给回调 - 没有任何东西可以挂起
this指针。我已经看到了一种解决这种情况的方法——一个动态生成的机器代码 thunk,其中嵌入了this指针——但我没有资格实际编写一个,而且它非常不便携。在任何情况下,您使用boost::function进行的游戏都将无法运行 - 无论您将多少奇怪的演员串在一起,您都无法凭空提取丢失的信息。
标签: c++ class pointers c++11 boost