使用 Toluapp 實作虛擬函式 |
|
需要 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 個可變更的旗標(可以在檔案開頭找到)。
disable_virtual_hooks
:快速旗標用於停用整體功能。如果設為 true
,將不會為虛擬函式產生任何特殊程式碼。enable_pure_virtual
:啟用對於純虛擬函式的支援。如果設為 false
,輸出程式碼在遇到擁有純虛擬函式的類別時將會「保守」。不會輸出建構函式,而程式碼只能搭配 GCC 4 編譯(透過預處理器開關),它對於純虛擬類別的接受度較高。default_private_access
:這是完全啟用 ToluappClassAccessLabels 程式碼的旗標。預設情況下,tolua++ 將類別的內容視為 public
,但由於我們可能有 private
虛擬函式,因此有一個選項,也可以在 pkg 檔案中將存取設為 private
。
由於 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