使用 Toluapp 實作虛擬函式

lua-users home
wiki

這個 tolua++ 外掛可用於產生程式碼,讓 c++ 虛擬函式能夠從 Lua 實作。此程式碼是 lua_qt 使用的程式碼修改版,結合 ToluappClassAccessLabels 以實作存取標記。請注意,這並不是一個補丁程式;它可以用在未修改的 tolua++ 二進位檔(版本 1.0.7 或更新版本)。

需要 2 個檔案

檔案:wiki_insecure/users/ArielManzur/tolua++/virtual_method_hooks.lua

檔案:wiki_insecure/users/ArielManzur/tolua++/tolua_base.h

使用範例

建立一個 .pkg 檔案

// mypackage.pkg

$#include "tolua_base.h"

class Widget {

protected:
   virtual bool input_event(Event* e);

public:

   virtual void add_child(Widget* child);

   void close();

   Widget(string p_name);
};

產生套件

tolua++ -L virtual_method_hooks.lua mypackage.pkg > mypackage.cpp
(compile 'mypackage.cpp' with the rest of the code)

從您的 Lua 腳本使用類別 Lua__Widget

-- custom_widget.lua
require "mypackage"

local CustomWidget = {}
CustomWidget.__index = CustomWidget

function CustomWidget:input_event(e)

   if e.type = Event.KEY_PRESS and e.key_code == KEY_ESCAPE then
      -- close the widget when escape is pressed
      self:close()
      return true
   end

   -- call Widget::input_event
   return self:Widget__input_event(e)
end

function CustomWidget:new(name)

   -- create a table and make it an 'instance' of CustomWidget
   local t = {}
   setmetatable(t, CustomWidget)

   -- create a Lua__Widget object, and make the table inherit from it
   local w = Lua__Widget:new(name)
   tolua.setpeer(w, t) -- use 'tolua.inherit' on lua 5.0

   -- 'w' will be the lua object where the virtual methods will be looked up
   w:tolua__set_instance(w)

   return w -- return 't' on lua 5.0 with tolua.inherit
end

在此範例中,類別「Lua__Widget」會被產生出來。Lua__Widget 擁有 Widget 的所有建構函式,以及一個函式「tolua__set_instance」,用於提供 Lua 物件,其中可以找到虛擬函式(在此情況中,我們使用與 c++ 物件相同的使用者資料物件,因為我們的 Lua 函式會覆寫 c++ 函式)。此物件將在 Lua 函式中傳遞為「self」。Lua__Widget 也會公開 Widget 的虛擬函式,直接被呼叫。

繼承

繼承自擁有虛擬函數類別的子類別,也會產生用於從 Lua 實作這些函式的程式碼,但只有當子類別本身具有任何虛擬函數時。例如,如果我們將下列內容加入我們的 pkg

class Label : public Widget {

public:
   void set_text(string p_text);
};

這 **不會** 產生 Lua__Label 類別。為此,我們需要至少加入一個虛擬函式。考慮以下範例

class Label : public Widget {

private:
   virtual void add_child(Widget* child);

public:
   void set_text(string p_text);
};

在這種情況下,唯一可用於類別 Lua__Label 的虛擬函式將會是 input_event(從 Widget 繼承而來)。在 pkg 中宣告 add_child 為私人函式的理由是,如果該函式實際上是私有的,而我們沒有在 pkg 中這樣宣告的話,產生出來的程式碼會嘗試在 Lua__Label 上使用它,這會產生編譯錯誤。

微調

virtual_method_hooks.lua 檔案有 3 個可變更的旗標(可以在檔案開頭找到)。

覆載

由於 lua 並不強制函數簽章,尋找函數的唯一方式是使用其名稱,因此當存在多個具有相同名稱的 c++ 方法時,lua 函數應準備好處理所有版本的函數。

另外,在尋找父類別的方法時,僅使用名稱來進行比對(這是目前版本的限制)。例如,如果您將此內容加入範例套件

class Button : public Widget {

public:
   virtual void add_child(Label* child);
};

僅最後一個版本的 add_child 將可供類別 Lua__Button 使用。

其他限制

目前僅支援一層名稱空間。為了避免無限遞迴,僅從虛擬方法呼叫 lua 函數(而非 lua_cfunctions)。

某些版本的 tolua++(例如 1.0.92)會出現與 'default_private_access' 旗標相關的問題。如果您的虛擬類別中的方法尚未匯出,請嘗試將旗標設為 false。您必須在預設為私有存取權限的類別宣告中,於開頭加入 private: 標籤。

聯絡

將問題、錯誤或意見傳送至 mailto:puntob@gmail.com


近期變更 · 喜好設定
編輯 · 歷史紀錄
最近編輯時間:2009 年 1 月 20 日 下午 7:38 GMT (diff)