2016-09-27 67 views
1

例如,有C++編寫的類繼承LUA:如何從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 library\n"); 
    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類LUA:

-- 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 

打印的結果並沒有出現無論是在盧阿通話和c成功地繼承++撥打:

[C] now loading the SWIG wrapped library 
It should not be show.. 
It should not be show.. 

我知道它是在繼承支持C++在Java中:generating-java-interface-with-swig

我知道在這裏過類似的問題,但確實不是G我面對的具體問題的答案:implementing-and-inheriting-from-c-classes-in-lua-using-swig

Lua支持是否繼承了使用SWIG的lua中的C++類,甚至只是使用純粹的lua?請顯示一些代碼示例。 如果SWIG不能完成這項工作,它是否有一些第三方庫支持可以輕鬆完成?

回答

0

看來SWIG with Lua doesn't actually support directors,這是跨語言多態性的工作所需要的。這不是世界末日,看起來你的SaySomething方法是Say類中唯一的虛擬方法,所以你可以用一個單一的回調函數代替。 (如果是我,我會在C++界面設計中使用std::function,這簡化了本工作的其餘部分)。

爲了說明這可能是如何工作的(並且在這個過程中學習了一些Lua!)我把一個演示放在一起,這個演示在你的測試用例中稍微簡化了一下。

實質上,我最終所做的是修改Callback類的類型的'in'類型映射表,以便使用luaL_ref保留對匿名函數的「引用」,如果給出的輸入不是回調類型開始。因此,我的類型映射檢查給出了它的類型,並構造一個臨時局部類型的實例,該類型繼承自Callback類型,持有並使用對某些Lua定義代碼的引用,直到我們用lua_pcall調用該類型。由於我們只在調用期間保存該實例,我們稍後將其清理到一個argfree類型映射中。(我的想法這從a Lua mailing list post

所以我的界面,演示了這一切在一個地方是這樣的:

%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 

注意是t他的例子幾乎翻了一番,我曾經寫過的Lua的總量,所以你真的應該檢查我在做生產之前所做的是否明智。如果你更熟悉Lua,可能會使用類似這樣的方法將適當的導向器支持添加到SWIG中,或者更好地模擬它(即,一種類型中有多個虛擬函數)。