我试图在 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);
}
};
然后我在主程序中只执行一次代码来尝试,我希望看到 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>*/);
}
};
最佳答案
如果 MyClass
只是一个单例,那么您可以很容易地使用静态成员来做到这一点。不幸的是,由于您正在创建 MyClass
的多个实例,因此您没有太多选择。你要么需要一些东西来挂起 this
指针,就像 Igor Tandetnik 说的那样,要么你需要一个可以安全地转换为函数类型的闭包,而 C++11 不提供。它需要动态创建的机器代码来实际实现类似的东西,而 GNU C(不是 C++)编译器是我所知道的唯一可以为您做到这一点的编译器。
我对 RakNet 不熟悉,但我在网络上进行了一些搜索,可以这么说,它看起来几乎没有给你一些东西来挂起 this
指针。 RPC 函数传递的 RPCParameters
指针包含一个名为 recipient
的 RakPeerInterface
指针,它应该指向相同的 RakClient
用于注册 RPC 函数的 RakClientInterface
指针所指向的对象。假设 MyClass
的每个实例只有一个 RakClient
对象,您可以使用 RakClient
的地址作为到 MyClass
的映射> 创建它的对象。
我已经发布了一个完整的示例来演示如何执行此操作。它不是实际使用 RakNet,而是使用相关类的骨架实现。我不清楚你使用的是什么版本的 RakNet(大多数实现似乎有 uniqueID
类型的参数 char const *
而不是 int *
),但只要 RPCParamters
有一个 recipient
指针,这种技术就应该有效。
#include <stdint.h>
#include <assert.h>
#include <stdio.h>
#include <map>
struct RakPeerInterface;
struct RPCParameters {
RakPeerInterface *recipient;
};
typedef void (*rakrpcfunc)(RPCParameters *rpcParams);
struct RakPeerInterface {
virtual void RegisterAsRemoteProcedureCall(int *, rakrpcfunc) = 0;
};
struct RakPeer: RakPeerInterface {
virtual void
RegisterAsRemoteProcedureCall(int *, rakrpcfunc func) {
RPCParameters params;
params.recipient = this;
func(¶ms);
}
};
struct RakClientInterface {
virtual void RegisterAsRemoteProcedureCall(int *, rakrpcfunc) = 0;
};
struct RakClient: RakPeer, RakClientInterface {
virtual void
RegisterAsRemoteProcedureCall(int *id, rakrpcfunc func) {
return RakPeer::RegisterAsRemoteProcedureCall(id, func);
}
};
struct RakNetworkFactory {
static RakClientInterface *
GetRakClientInterface() {
return new RakClient;
}
};
class MyClass;
typedef void (MyClass::*rpcmethod)(RPCParameters *rpcParams);
template <rpcmethod method>
class rak_thunk {
static std::map<RakClient *, MyClass *> clientmap;
static void thunk(RPCParameters *rpcParams) {
RakPeerInterface *pip = rpcParams->recipient;
RakClient *cp = dynamic_cast<RakClient *>(pip);
return (clientmap[cp]->*method)(rpcParams);
}
public:
static rakrpcfunc
make_thunk(MyClass *this_, RakClientInterface *cip) {
RakClient *cp = dynamic_cast<RakClient *>(cip);
assert(clientmap[cp] == NULL || clientmap[cp] == this_);
clientmap[cp] = this_;
return thunk;
}
};
template <rpcmethod method>
std::map<RakClient *, MyClass *> rak_thunk<method>::clientmap;
int RPC_ServerJoin;
class MyClass {
RakClientInterface *pRakClient;
void
MyFunction(RPCParameters *pParams) {
printf("MyClass(%s)::MyFunction called\n", name);
}
typedef void (MyClass::*rpcmethod)(RPCParameters *rpcParams);
char const *name;
public:
MyClass(char const *s): name(s) {
pRakClient = RakNetworkFactory::GetRakClientInterface();
if (pRakClient == NULL)
return;
rakrpcfunc p = (rak_thunk<&MyClass::MyFunction>
::make_thunk(this, pRakClient));
pRakClient->RegisterAsRemoteProcedureCall(&RPC_ServerJoin, p);
}
};
int
main() {
MyClass a("a");
MyClass b("b");
}
此示例在 Windows 下使用 GNU C++ 4.8.1 和 Visual Studio 2013 C++ 编译器编译和运行。值得注意的是,它不使用 Boost 或任何花哨的新 C++11 功能。
关于c++ - 如何像普通 C 函数一样使用正确的 'this' 指针调用 C++ 类成员函数? (指向类成员函数的指针),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25231851/