簡體   English   中英

如何使用SWIG從Lua中的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 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中做的是從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 ++調用中,打印結果似乎都無法成功繼承:

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

我知道它支持從Java中的C ++繼承: 生成帶有斜杠的java-interface-with

我知道這里有一個類似的問題,但是沒有給出我要面對的具體問題的答案: 在Lua中使用Cwig實現和繼承C類

Lua是否支持使用SWIG從lua中的C ++類繼承,甚至僅使用純lua? 請顯示一些代碼示例。 如果SWIG無法完成這項工作,那么它是否具有一些第三方庫支持來輕松​​完成此工作?

帶有Lua的SWIG似乎實際上並不支持Director ,這是跨語言多態性起作用所必需的。 不過,這還不是世界末日,看起來您的SaySomething方法是Say類中唯一的虛擬方法,因此您可以替代單個回調函數。 (如果是我,我會在C ++接口設計中使用std::function ,從而簡化了其余工作)。

為了展示它是如何工作的(並向我學習一些Lua!),我整理了一個演示,該演示相對於問題中的測試用例略有簡化。

本質上,我最終要做的是修改Callback類的“ in”類型luaL_ref以使用luaL_ref保留對匿名函數的“引用”, luaL_ref是輸入的內容不是回調類型的開始用。 因此,我的類型映射檢查了給定的類型,並構造了一個臨時的本地類型的實例,該實例從Callback類型繼承,保留並使用對Lua定義的代碼的引用,直到我們使用lua_pcall對其進行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總量增加了幾乎一倍,因此您真的應該在將其用於生產之前檢查我所做的事情是否合理。 可能可以使用類似這樣的方法在SWIG中添加適當的Director支持,或者如果您更熟悉Lua,則可以更好地模擬它(即,一個類型中有多個虛擬函數)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM