繁体   English   中英

如何像正常的C函数一样使用正确的“ this”指针调用C ++类成员函数? (指向类成员函数的指针)

[英]How do I call a C++ Class member function with the correct 'this' pointer like a normal C function? (pointer to class member function)

我想打电话给像升压的帮助下,正常的C函数的类成员函数,但我的努力 寻找 如何 做到这一点完全感觉不到,所以我想出了我自己的东西,这东西听起来很直观的......我认为。

但是问题在于,当调用指向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);
    }
};

然后,我仅在主代码中执行一次代码以进行尝试,我希望看到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)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多个实例,因此您没有太多选择。 就像Igor Tandetnik所说的那样,您可能需要挂this指针的东西,或者需要可以安全地转换为函数类型的闭包,而C ++ 11不提供该闭包。 它需要动态创建的机器代码才能真正实现类似的功能,而GNU C(不是C ++)编译器是我所知道的唯一可以为您做到这一点的编译器。

我对RakNet并不熟悉,但是我在网络上进行了一些搜索,因此看起来它几乎没有给您一些东西来挂this指针。 RPCParameters指针RPC函数传递包含RakPeerInterface指针名为recipient应引起指向同RakClient所指向的对象RakClientInterface指针用于注册的RPC功能。 假设MyClass每个实例只有一个RakClient对象,则可以使用RakClient的地址映射到创建它的MyClass对象。

我已经发布了一个完整的示例,演示了如何执行此操作。 它不是实际使用RakNet,而是使用相关类的框架实现。 我不清楚您使用的是哪个版本的RakNet(大多数实现似乎具有char const *而不是int *类型的uniqueID参数),但是只要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(&params);
    }
};

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新功能。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM