来自C ++的Lua回调

时间:2013-11-20 16:29:49

标签: c++ lua

我有一个c ++主机,我使用tolua ++将一些类暴露给Lua。其中一个类有一个应该从lua注册回调的函数。因此,当C ++代码需要调用Lua注册函数时,它可以。然而,该函数是表/类函数。之前我已经用字符串函数名称(不是lua“类”的一部分)成功完成了这个,但是我很好奇我是否能以某种方式存储Lua函数而不是函数名。

我定义了我的lua类,如:

MyClass = {}

function MyClass:Create()
    local obj = {}

    -- copy all functions from MyClass table to this local obj and return it
    local k,v
    for k,v in pairs(obj) do
        obj[k] = v
    end

    return obj
end

function MyClass:Enter()
    self.CPlusClass = CPlusClass:Create()   -- this is the C++ class creation, I defined a static function Create()
    self.CPlusClass:RegisterCallback(15, self.Callback) -- this is where I want to pass this instances function to be called back from the C++ class
end

function MyClass:Callback(reader)
    -- I want to be able to use self here as well so it needs to be the same instance
end

在MyClass中:Enter()是我想要注册lua“class”函数MyClass :: Callback的地方,可以从C ++对象中调用它。我如何将其传递给C ++函数?类型是什么,它将调用MyClass:来自C ++的Callback()也传入“self”,这样它就是类的“实例”?

所以我知道'self'指的是我创建的实际变量,我假设它将在变量名称的全局表中,但是当你在lua“class”里面时,我怎么能告诉变量名'self '也指的是?如果我能得到它我可以将它传递给我的C ++函数并将其存储为字符串,以便我可以调用getglobal来获取该特定的表,然后我也可以将表函数名称作为字符串传递给C ++我可以得到它,并称之为。但问题是,如何将'self'转换为它指向的实际变量名称,以便我可以在C ++中调用getglobal来获取该表?

2 个答案:

答案 0 :(得分:3)

您将CPlusClass“class”从C ++导出到Lua:当然这个C ++类有一个RegisterCallback,它接受一个指向函数的指针或一个使用虚方法调度到正确对象的YourCallbackClass实例。然后你需要的是将YourCallbackClass导出到Lua:在幕后,Lua版本将创建一个实例并将其提供给你的C ++ RegisterCallback。 例如:

class CPlusClass {
public: 
    RegisterCallback(int val, CPlusCallback* cb) { ... store cb for later... }
};

class SomeObj; // type of Objects that you want to call back into

class CPlusCallback {
public:
    typedef void (SomeObj::*Method)();
    CPlusCallback(SomeObj* obj, Method method) { callee=obj; method=method; }
    call() { callee->*Method(); }
private:
    SomeObj* callee; 
    Method method;
};

你的CPlusCallback可能不同,这只是一个例子。例如,如果您只想要函数而不是方法,那么您不需要存储被调用者。如果你想要两者,那么CPlusCallback必须是基类,call()是虚拟的,派生类适当地实现细节。适应您的情况。

然后将CPlusCallback和SomeObj导出到Lua,然后你可以在Lua中执行:

somObj = SomeObj:Create()

function MyClass:Enter()
    -- creates Lua instance of CPlusClass, with a user data for the C++
    -- counterpart as member
    self.CPlusClass = CPlusClass:Create()  
    self.CPlusCallback = CPlusCallback:Create(someObj, someObj.method)
    self.CPlusClass:RegisterCallback(15, self.CPlusCallback)
end

其中上面假设someObj.method是您从C ++类SomeObj导出的方法,具有正确的签名void(SomeObj :: * Method)()。

答案 1 :(得分:2)

如果你想保留RegisterCallback签名和操作(而不是增强它以某种方式理解对象方法回调),那么你需要创建一个闭包并将其作为回调传递。像这样:

function create_closure(obj, fun)
    return function(...)
        return obj[fun](...)
    end
end

function MyClass:Enter()
    self.CPlusClass = CPlusClass:Create()   -- this is the C++ class creation, I defined a static function Create()
    self.CPlusClass:RegisterCallback(15, create_closure(self, "Callback"))
end