如何使用正确的'这个'来调用C ++类成员函数?指针就像一个普通的C函数? (指向类成员函数的指针)

时间:2014-08-10 18:43:48

标签: c++ class pointers c++11 boost

我试图在boost的帮助下调用类成员函数,就像普通的C函数一样,但我的efforts into looking how to这样做只是失败所以我自己想出了一些东西,听起来很直观......我想。

但问题是,在调用指向boost::function - fooAfooB的指针时,它会一直崩溃。

对它进行一些测试:

#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*),但我需要将它封装在一个类中。该库使用Callbacks来通知任何更改。所以我需要想办法将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>*/);
    }
};

1 个答案:

答案 0 :(得分:1)

如果MyClass只是一个单身,那么你可以很容易地使用静态成员。不幸的是,因为你正在创建MyClass的多个实例,所以你没有很多选择。就像Igor Tandetnik所说的那样,您需要挂起this指针的东西,或者您需要一个可以安全地转换为函数类型的闭包,而C ++ 11并不提供。它需要动态创建的机器代码来实际实现类似的东西,GNU C(而不是C ++)编译器是我所知道的唯一可以为你做这件事的编译器。

我对RakNet并不熟悉,但我在网上进行了一些搜索,看起来它几乎没有给你一些东西来悬挂this指针,可以这么说。 RPC函数传递的RPCParameters指针包含一个名为RakPeerInterface的{​​{1}}指针,该指针应指向recipient指向的同一RakClient对象用于注册RPC函数的指针。假设每个RakClientInterface实例只有一个MyClass对象,您可以使用RakClient的地址作为映射到创建它的RakClient对象。

我发布了一个完整的示例,演示了如何执行此操作。它不是实际使用RakNet,而是使用相关类的框架实现。我不清楚你使用的是什么版本的RakNet(大多数实现似乎都有MyClass类型的uniqueID参数,而不是char const *),但只要int *有这个技术应该有RPCParamters指针。

recipient

此示例使用Windows下的GNU C ++ 4.8.1和Visual Studio 2013 C ++编译器进行编译和运行。值得注意的是,它不使用Boost或任何花哨的新C ++ 11功能。