如何在lua中使用SWIG继承c++类
How to inherit from C++ class in lua using SWIG
例如,有一个用c++编写的类:
//Say.h
#pragma once
#include <iostream>
class Say
{
public:
Say() {}
virtual ~Say() {}
virtual void SaySomething() { std::cout << "It should not be show..n"; };
};
inline void CallCppFun(Say& intf) {
intf.SaySomething();
}
和我写的Say.i:
//Say.i
%module Test
%{
#include "Say.h"
%}
%include "Say.h"
%inline %{
inline void CallCppFun(Say& intf);
%}
和main.cpp:
//main.cpp
#include <iostream>
extern "C"
{
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}
/* the SWIG wrappered library */
extern "C" int luaopen_Test(lua_State*L);
using namespace std;
int main()
{
lua_State *L;
L = luaL_newstate();
luaL_openlibs(L);
printf("[C] now loading the SWIG wrapped libraryn");
luaopen_Test(L);
if (luaL_loadfile(L, "Test.lua") || lua_pcall(L, 0, 0, 0)) {
printf("[C] ERROR: cannot run lua file: %s", lua_tostring(L, -1));
exit(3);
}
return 0;
}
,然后运行命令:
swig -c++ -lua say.i
我编译了自动生成的文件example_wrap。CXX和其他CPP文件链接成功。
我想在Test中做什么。lua是从c++的Say
类继承的:
-- Test.lua
Test.Say.SaySomething = function(self)
print("Inherit from C++ in Lua")
end
my = Test.Say()
my:SaySomething() -- doesn't appear to inherit successfully in lua call
Test.CallCppFun(my) -- doesn't appear to inherit successfully in c++ call
在lua调用和c++调用中print的结果似乎都没有继承成功:
[C] now loading the SWIG wrapped library
It should not be show..
It should not be show..
我知道它是在继承c++在Java中的支持:
我知道这里有一个类似的问题,但没有给出我所面临的具体问题的答案:实现和继承c-classes-in-lua-using-swig
Lua支持继承c++类在Lua使用SWIG或甚至只是使用纯Lua ?请展示一些代码示例。如果SWIG不能完成这项工作,它是否有一些第三方库支持来轻松完成?
看起来使用Lua的SWIG实际上并不支持董事,而董事是跨语言多态性工作所必需的。这并不是世界末日,看起来你的SaySomething
方法是Say
类中唯一的虚方法,所以你可以用一个回调函数来代替。(如果是我,我会在c++接口设计中使用std::function
,这简化了其余部分的工作)。
来展示这是如何工作的(并在此过程中学习一些Lua !)我整理了一个演示,它比问题中的测试用例稍微简化了。
本质上,我最终要做的是修改Callback
类的"In"类型映射,使用luaL_ref
保留对匿名函数的"引用",如果输入它所给出的不是回调类型开始。因此,我的typemap检查给定的类型,并构造一个临时的本地类型的实例,该实例继承Callback
类型,保存并使用对一些Lua定义的代码的引用,直到我们用lua_pcall
调用它。由于我们只在调用期间持有该实例,因此稍后将其清理到一个argfree类型映射中。(我从一个Lua邮件列表帖子中得到了这个想法)
所以我的界面在一个地方展示了这一切,看起来像这样:
%module test
%{
#include <iostream>
%}
%typemap(in) const Callback& (Callback *tmp=NULL) %{
if(lua_isuserdata(L,$argnum)) {
if (!SWIG_IsOK(SWIG_ConvertPtr(L,$input,(void**)&$1,$descriptor,$disown))){
SWIG_fail_ptr("$symname",$argnum,$descriptor);
}
}
else if (lua_isfunction(L,$argnum)) {
struct Lua$basetype : $basetype {
Lua$basetype(lua_State* L, int idx) : L(L) {
lua_pushvalue(L, idx); // This gets popped by luaL_ref
// retain our argument
ref = luaL_ref(L, LUA_REGISTRYINDEX);
}
virtual ~Lua$basetype() {
// release our reference
luaL_unref(L, LUA_REGISTRYINDEX, ref);
}
virtual void run(const std::string& str) const {
// push our 'reference' onto the stack
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
// manually prepare the function arguments
lua_pushstring(L, str.c_str());
// make the actual calll
lua_pcall(L, 1, 0, 0);
// TODO: catch error and throw as C++ exception?
}
private:
lua_State* L; // Uh, is keeping this around bad?
int ref;
};
tmp = new Lua$basetype(L,$input);
$1 = tmp;
}
else {
SWIG_fail_arg("$symname",$argnum,"$1_type");
}
%}
%typemap(freearg) const Callback& %{
delete tmp$argnum; // Fine, even if NULL remember
%}
%inline %{
struct Callback {
virtual ~Callback() {}
virtual void run(const std::string& str) const { std::cout << "Got string: " << str << "n"; }
};
void call_me(const Callback& cb) {
std::cout << "Hello World:n";
cb.run("DO IT NOW");
}
%}
这就足够了,我可以在下面的Lua代码中使用它:
require("test")
cb=test.Callback()
test.call_me(cb)
cb=function(s) print("Lua got string: "..s) end
test.call_me(cb)
我可以编译和运行:
swig3.0 -lua -c++ test.i
g++ -Wall -Wextra test_wrap.cxx -shared -o test.so -I /usr/include/lua5.1/
lua run.lua
Hello World:
Got string: DO IT NOW
Hello World:
Lua got string: DO IT NOW
请注意,这个例子几乎是我编写的Lua总数的两倍,所以在将其用于生产环境之前,您真的应该检查我所做的是明智的。如果你更熟悉Lua的话,也许可以使用类似的东西在SWIG中添加适当的导演支持,或者更好地模拟它(即在一个类型中有多个虚拟函数)。
- 继承函数的重载解析
- 继承期间显示未知行为的子类
- 头文件-继承c++
- 为什么在保护模式下继承升级不起作用
- 通过继承类使用来自不同命名空间的运算符
- Python 3.7 和 excess_args 的 SWIG 问题
- 子目录是否继承属性,例如add_definitions,include_directories和父Cmakelist.t
- 混合组合和继承的C++问题
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 从类继承时,继承的类是否会通过父类重新定义继承的变量
- 公共与私人继承
- 如何创建从同一类继承的不同对象的向量
- 如何从另一个文件继承私有成员变量和公共函数
- 在模板基类中为继承类中的可选重写生成虚拟方法
- 从具有默认值的部分指定模板类继承时发生SWIG错误,具有不带默认值的正向声明
- 在Python类(SWIG)中使用从抽象c++类继承的方法
- 如何在lua中使用SWIG继承c++类
- 在Python中继承c++的Base,使用SWIG调用抽象方法
- 处理来自 SWIG 中自身专用实例的类继承
- SWIG JAVA 如何使用 %interface 和纯虚拟方法包装C++多重继承