我有一个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++函数中?该类型是什么样的,它将从C++调用MyClass:Callback(),同时传入"self",使其成为类的同一"实例"?
所以我知道"self"指的是我创建的一个实际变量,我假设它将按变量名在全局表中,但当你在lua"class"中时,我怎么能知道"self-"也指的是什么变量名?如果我能得到,我可以把它传递给我的C++函数,并将其存储为字符串,这样我就可以在它上调用getglobal来获得特定的表,然后我也可以把表函数名传递为字符串,在C++中我也可以得到它,并调用它。但问题是,如何将"self"转换为它所指向的实际变量名,以便在C++中调用getglobal来获取该表?
您将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)()。
如果您想保留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