tolua++ 參考手冊node
--劉源霖 (譯)程序員
本文是對tolua++官網使用手冊的翻譯,若是讀者在閱讀的過程當中什麼疑問可參考官方使用手冊。在本文中不會添加任何譯者的理解,徹底是安裝文章筆者的原文進行翻譯。數組
tolua++ 是tolua的一個擴展版本,是一個將C/C++代碼集成到lua中的工具。Tolua++增長了面向C++的新功能和bug修正,好比支持std::string做爲基礎類型(能夠經過命令行參數開關),支持模板類。框架
Tolua++工具集成C/C++代碼到lua很是的簡單方便,tolua可以基於一個簡單的頭文件(能夠從多個頭文件中提取)爲lua訪問C/C++功能自動生成綁定代碼。經過使用lua API 和一些標記方法,tolua能爲lua提供C/C++中的常數,外部變量,函數,類,方法。ide
該使用手冊是針對tolua++1.0版本,實現是基於lua5.0和tolua5.0。若是想了解相對舊版本的兼容性細節能夠訪問tolua++官網。下面部分我將描述如何使tolua,若是發現任何錯誤或者建議能夠聯繫tolua++官方團隊。函數
使用tolua,咱們須要建立一個pkg文件,即一個簡單的C/C++頭文件,該文件包括咱們想要綁定到lua中的常數,外部變量,函數,類,方法。而後使用tolua解析pkg文件,生成一個自動綁定C/C++代碼到到lua的C/C++文件,只要咱們將生成的文件連接到咱們的應用程序中,就能在lua中訪問咱們在pkg文件中指定的C/C++代碼,即咱們定義的常數,外部變量,函數,類,方法。一個pkg文件可以包含正規的C/C++頭文件、其餘pkg文件以及lua文件。工具
讓咱們一個例子開始,假定咱們指定綁定下面相似C 頭文件的pkg文件到lua中:性能
a.pkg測試
int foo(lua_State *L)this
#define FALSE 0
#define TRUE 1
enum {
POINT = 100,
LINE,
POLYGON
}
Object* createObejct (int type);
void drawObject (Object* obj, double red, double green, double blue);
int isSelected (Object* obj);
使用tolua++解析a.pkg生成一個自動綁定上面代碼的C文件,連接到咱們的應用中,而後咱們能夠在lua中這樣使用綁定的C 代碼, 用一個實例來表示:
a.lua
...
myLine = createObject(LINE)
...
if isSelected(myLine) == TRUE then
drawObject(myLine, 1.0, 0.0, 0.0);
else
drawObject(myLine, 1.0, 1.0, 1.0);
end
...
一樣,導入一個類C++的頭文件:
b.pkg
#define FALSE 0
#define TRUE 1
class Shape
{
void draw (void);
void draw (double red, double green, double blue);
int isSelected (void);
};
class Line : public Shape
{
Line (double x1, double y1, double x2, double y2);
~Line (void);
};
用tolua解析這個文件,將會自動生成一個C++文件,該文件綁定上面的code到lua中,導入的代碼能夠下面這樣有效的使用:
...
myLine = Line:new (0,0,1,1)
...
if myLine:isSelected() == TRUE then
myLine:draw(1.0,0.0,0.0)
else
myLine:draw()
end
...
myLine:delete()
...
提供給tolua解析的這個pkg文件(一般用擴展名.pkg表示)不是一個真正的C/C++頭文件,可是是真正C/C++頭文件的一個更簡潔的版本。Tolua沒有實現徹底的解析C/C++代碼,可是它能解析一些的聲明,這些聲明是用來描述咱們要導入到lua的功能。正規的頭文件能夠包含在pkg文件中,tolua將從頭文件中提取用戶指定的代碼進行解析。
Tolua 由兩部分組成:一個可執行文件和一個庫文件。這個可執行文件就是一個解析器,它讀取pkg文件進行解析,輸出一個對應的C/C++文件,這個C/C++實現了自動綁定pkg文件中指明的code到lua中,讓lua中可以正常的訪問。若是這個pkg文件是一個相似於C++的頭文件(即包含類的定義),那麼將自動生成一個C++文件,若是這個pkg文件是一個相似於C的頭文件,那麼將自動生成一個C文件,tolua命令支持帶參數運行,運行「tolua –h」 能夠查看當前tolua命令支持的參數集。例如,利用tolua解析一個名爲myfile.pkg的文件生成其綁定代碼到myfile.c文件中,咱們能夠用命令:
tolua –o myfile.c myfile.pkg
這生成的文件必須編譯,而且連接到咱們的應用程序中,這樣才能爲lua提供訪問,每個解析的文件被看成一個包導入到lua中。默認狀況下,這個包名就是導入文件的根文件名(在上一個例子中包名就是myfile)。用戶還能夠指定不一樣報名:
tolua –n pkgname –o myfile.c myfile.pkg
這個包必須被明確的初始化。爲了在C/C++代碼中初始化這個包,咱們必須聲明和調用這個初始化函數,這個初始化函數被定義爲:
Int tolua_pkgname_open(lua_State *);
其中pkgname就是咱們要初始化的包名。若是咱們使用的是C++,咱們還能夠選擇自動初始化:
Tolua –a –n pkgname –o myfile.c myfile.pkg
這中狀況下,這個初始化函數將會自動被調用,可是若是咱們計劃使用多個lua states,則不能使用自動初始化,由於那些在C++中被初始化的靜態變量的順序沒有被定義。
這個open函數的原型也能夠選擇輸出到一個頭文件中,這個頭文件名字能夠用—H 選項指定。
tolua自動生成的綁定代碼使用了tolua庫中的函數集,因此這個庫必須被連接到咱們的應用程序中。自動生成的綁定代碼中必須包含頭文件tolua.h。
一個應用程序能夠不綁定任何包,直接使用tolua提供的面向對象框架(具體見通用函數導出章節),可是必須調用tolua的初始化函數(這個函數在任何的包初始化函數中被調用):
Int tolua_open(void);
使用tolua的第一步是建立一個pkg文件。以一個真實的頭文件開始,我須要按照tolua可以解析的格式去清理咱們項目想要導入到lua中的功能。這tolua可以解析的格式是如下方式描述的一個簡單的C/C++聲明。
一個pkg文件可能包含其餘pkg文件,其格式以下:
$pfile 「include_file」
一個pkg文件可能包含正規的C/C++頭文件,用hfile 或者cfile指令:
$cfile 「example.h」
在這種狀況下,tolua將會提取在「tolua begin」 和 「tolua_end」之間的代碼,或者用「tolua_export」指定的單行代碼。如下面的C++頭文件爲例:
#ifndef EXAMPLE_H
#define EXAMPLE_H
Calss Example { //tolua_export
private:
string name;
int number;
public:
void set_number(int number);
//tolua_begin
string get_name();
int get_number();
};
//tolua_end
#endif
在這個例子中,不被tolua支持的代碼(類的私有變量)和函數set_number 將會被捨棄,不會包含到pkg文件中。
最後,lua文件也能夠包含在pkg文件中,使用「$lfile」:
$lfile 「example.lua」
tolua++ 擴展:
從版本1.0.4開始新增長了一個包含資源文件的擴展方法,使用命令:$ifile:
$ifile "filename"
Ifile 一般在文件名的後面使用附件參數, 例如:
$ifile "widget.h", GUI
$ifile "vector.h", math, 3d
Ifile的默認行爲是包含文件的緣由內容,可是,這包含文件的內容和擴展參數在包含進pkg文件前先要調用include_file_hook函數(細節前參考定製tolua++章節)。
Tolua 自動映射C/C++j接班類型到LUA的基本類型,所以:char, int , float,double被映射到Lua的number類型;char * 被映射成string;void * 被映射成userdata;每一個類型類型可能被加上前綴修飾語(unsigned, static, short, const, etc.);然而,假如基本類型前加上const,tolua將會忽略它。所以,假如咱們傳遞一個常數基本類型到lua,而後從lua再傳回給C/C++代碼時將會變成一個很是數類型,這種常數類型到很是數類型的轉換將被默認完成。
在C/C++函數中也能明確的使用lua對象,所以,「lua_Object」類被看做一個基本類型,任何的Lua 值均可以用lua_Object表示。
Tolua++ 擴展:
C++類型string 被看做基本類型,以及能夠被做爲一個值傳遞到lua中(使用c_str()方法)。這個功能能夠經過命令行參數-S關閉。
全部在pkg文件中出現過的其餘的類型被看做用戶定義類型,他們被映射成lua中標記的userdata類型。Lua僅僅可以存儲用戶定義類型的指針。儘管如此,tolua++會自動生成一些必要的步驟來處理引用和值。舉個例子,假如在函數或者方法中返回了一個用戶定義類型,當返回它到lua時,tolua分配一個克隆的對象以及設置其垃圾回收標記方法,以便在lua再也不使用時自動回收分配對象。
對於用戶定義類型,常量是被保存的。所以,傳遞一個很是量的用戶定義類型到一個須要參數是常量類型的函數中時將會產生一個類型不匹配的錯誤(type mismatch error)
C/C++ NULL或者0指針被映射成lua中的nil類型,相反的,nil能夠給任何一個C/C++指針。將char* ,void*以及指針轉換成用戶定義類型是有效的。
Tolua 也支持簡單的類型定義(typedef),一個類型被從新定義後,其後任何出現的地方都會被tolua映射成基本類型。這是很是有用的,每一個包能夠經過C/C++的基礎類型從新定義本身的類型。例,某個包能夠定義類型real 看成 double類型,這樣,real就能夠在pkg文件中定義變量的類型了。可是在咱們使用前必須包含以下的定義:
typedef double real;
不然,real將會被解釋成一個用戶定義類型,而不是lua的number類型。
在pkg文件中,咱們必須指定包含真正的頭文件,以致於tolua生成的代碼中可以正常的訪問咱們要綁定到lua中的常量,變量,函數,類等。在pkg文件中任何以$符號開始的一行(除$[hclp]file, $[ , $] 開頭行)將會不做任何修改的插入到生成的綁定代碼中,可是要去除$符號。咱們使用這個功能來包含真正的頭文件,因此,一般在pkg文件的開始位置咱們會用$符號包含咱們指定的頭文件,這些頭文件是咱們pkg文件的基礎。
/* specify the files to be included */
$#include "header1.h" // include first header
$#include "header2.h" // include second header
從上面的代碼能夠看出,tolua也接受註釋,註釋使用C/C++習慣方式。
一樣能夠注意到使用$hfile 或者 $cfile 不須要使用include這種方式,這些被toulua自動完成了。
在接下的章節中,咱們將描述如何指定咱們想要綁定到lua中的C/C++代碼, 這格式是一個簡單的有效的C/C++聲明。
爲了綁定常量,tolua支持define和enum,對於define的支持其格式以下:
#define NAME [VALUE]
VALUE 是可選的,將上面的代碼包含在pkg文件中,tolua生成的綁定代碼容許lua中把NAME看成一個全局變量使用,而且其值和C/C++中的值同樣。可是僅僅只支持數值常量。
Tolua++ 擴展:因此其餘預處理將會被忽略。
對於enum支持格式以下:
enum {
NAME1 [ = VALUE1 ] ,
NAME2 [ = VALUE2 ] ,
...
NAMEn [ = VALUEn ]
};
一樣的,tolua建立了多個全局變量,以及他們對應的值。
全局的外部變量能夠被導出,在pkg文件中的他們的指定格式以下:
[extern] type var;
Tolua綁定此聲明到Lua的全局變量中,所以在Lua中咱們可以天然的訪問C/C++變量,假如這個變量是一個很是量,咱們在lua中爲其賦新值。全局數組也能夠綁定到亂中,數組能夠是任何類型,與之對應的lua對象是table,table的以數字作索引,只是table中時從1開始,而數組中是從0開始。例:
double v[10];
tolua++擴展:外部變量咱們能夠用tolua_readonly 修飾(見附件功能章節)
函數的指定按照日常的C/C++函數聲明:
type funcname (type1 par1[, type2 par2[,...typeN parN]]);
這返回的類型能夠是空,意味着沒有值返回。函數也能夠沒有參數,參數鏈表用void表示。參數類型必須準信以前的說明的規則。Tolua建立一個Lua 函數 綁定這個C/C++函數,在lua中調用這個函數時,參數類型必須匹配,不然toua將會生成錯誤信息,而且報告那個參數有錯誤。假如參數的名字是省略的,tolua將會自動爲期命名,可是其類型必須是基本類型或者以前已經定義的用戶類型。
Tolua也可以處理函數或者方法參數是數組時,數組參數對應lua中的table,數組的長度必須提早預約,例:
void func (double a[3]);
對tolua上面是一個有效的聲明,綁定後在lua中能夠直接調用該函數,例:
p = {1.0,1.5,8.6}
func (p)
數組的維數不必定是一個參數表達式,能夠任何一個能夠在運行計算的表達式,例:
void func (int n, int m, double image[n*m]);
可是上面這種使用方法,tolua是使用動態分配法來綁定函數的,因此其性能要低一些。
儘管規定了數組的大小,可是咱們必須知道全部傳入實際C/C++函數的數組變量在綁定函數都是局部變量,因此,若是被調用的C/C++函數若是要保存數組的指針在函數調用後使用,那麼這綁定代碼將會出現異常。
重載函數也是被支持的,可是必須記住,兩個名字相同的函數的區別是基於其映射到lua中的參數類型。因此,儘管:
void func (int a);
void func (double a);
這兩個函數在C++中是不一樣的,可是他們對於lua來講是相同的函數,由於int和double映射到lua中的函數都是number類型。
還有另一種特殊的狀況,當全部的參數都是指針時,如:
void func (char* s);
void func (void* p);
void func (Object1* ptr);
void func (Object2* prt);
上面四個函數在C++中時不一樣的,可是在lua中用一個函數均可以匹配他們:
func(nil)
因此知道tolua是如何解決在運行時調用那個函數時很是重要的,其方法就是就是嘗試匹配沒一個提供的函數,首先匹配最後一個被指定的函數,假如失敗了,繼續匹配前一個被指定的函數,重複這過程,直到有函數匹配或者匹配到第一個被指定函數。若是匹配到第一個被指定函數都尚未匹配成功,那麼將會報告「mismatching error」 消息。但性能很重要時,咱們能夠將最經常使用的函數放在最後一個指定,由於它將第一個被匹配。
Tolua 運行在C中使用重載,細節請看「重命名「章節。
函數的最後幾個參數能夠指定默認值,這樣,在函數被調用時有默認值的參數能夠不傳入值,而是從默認值中獲取。在pkg文件總指定默認值的格式和C++中同樣。
type funcname (..., typeN-1 parN-1 [= valueN-1], typeN parN [= valueN]);
tolua 實現這個功能沒有使用任何的C++機制,因此它也能夠用於綁定C函數。
咱們也能夠爲數組的元素指定默認值(儘管沒有方法爲一個數組指定默認值),例:
void func (int a[5]=0);
上面代碼指定數組元素的默認值是0,因此這個函數在lua中可使用一個沒有被初始化的表來調用。
對於Lua object 類型(lua_object), tolua 定義了一個一個常理,它指定爲nil做爲一個默認值。
void func (lua_Object lo = TOLUA_NIL)
tolua++擴展:
C++構造器做爲默認參數是有效的,例:
void set_color(const Color& color = Color(0,0,0));
在lua中,一個函數能夠返回任意多個值,tolua使用這個功能經過引用模擬值傳
遞。假如一個函數的參數使用指針或者引用做爲參數類型,tolua將支持對應的類型做爲輸入而且返回對應的類型。
例:
void swap (double* x, double* y);
or
void swap (double& x, double& y);
假如這個函數被聲明在pkg文件中,tolua 將會以一個有兩個輸入參數,兩個返回值的函數綁定它。因此在lua中正確的調用:
x,y = swap(x,y)
使用默認值的狀況:
void getBox (double* xmin=0, double* xmax=0, double* ymin=0, double* ymax=0);
In Lua:
xmin, xmax, ymin, ymax = getBox()
使用用戶類型的狀況:
void update (Point** p);
or
void update (Point*& p);
Tolua完美的支持用戶定義類型綁定,對於不是基礎類型的變量類型或者函數類型,tolua會自動建立一個標記的userdata來看成這個類型。假如類型是一個結構體,這個結構體的域能夠直接在lua中訪問,在C代碼中,類型定義通用typedef:
typedef struct [name] {
type1 fieldname1;
type2 fieldname2;
...
typeN fieldnameN;
} typename;
假如上面的代碼被綁定到lua中,咱們能夠這樣訪問,假如var是上面類型的一個變量或者對象,咱們能夠經過var.fieldnamei 來訪問類型中域名爲fieldnamei的值。
通用支持域是數組的狀況:
typedef struct {
int x[10];
int y[10];
} Example;
Tolua支持C++中類的定義,實際上,tolua使用了一個天然的方法處理單繼承和多狀態的。接下來的部分描述了類中那些可以被導入到lua中。
假如var是一個lua變量,var保存了一個派生類對象,var能夠用於任何其基類的地方,而且var能夠訪問其基類的任何方法。爲了這一機制可以生效,咱們必須指明派生類繼承的基類。使用傳統的方法,以下:
class classname : public basename
{
/* class definition */
};
如在lua中要使用繼承的屬性, 那麼基類basename要在派生類classname前定義。
Tolua++從版本1.0.4開始支持多繼承,容許你手動的訪問其餘的父類。
例:
class Slider : public Widget, public Range {
...
};
一個Slider的對象將會徹底的繼承widget,以及會包含一個Range類型的成員,例:
For example:
slider = Slider:new()
slider:show() -- a Widget method
slider:set_range(0, 100) -- this won't work, because
-- set_range is a method from Range
slider.__Range__:set_range(0, 100) -- this is the correct way
這只是一個實驗功能。
對於結構體域,類域,靜態的或者非靜態的均可以被導出。類的方法和類靜態方法也能夠別導出。固然他們在C++中必須是被定義爲public的(這public: 關鍵之能夠保留在pkg文件中,它將會被tolua忽略)。
每個綁定的類,tolua建立一個lua表來存儲它,而且命令和C++類名同樣。這個表當中可能包含其餘表,表示這個類中可能包含其餘類或者結構體。靜態的方法經過表能夠直接調用,非靜態的必須經過對象訪問,即一個包含對象的變量。
Tolua支持一些特殊的方法。構造器被定義爲靜態的,名字爲new,new_local
(tolua++), 或者直接調用類名(具體的細節見下文),析構函數被定義爲delete方法。
注意tolua支持重載,這個能夠應用於構造函數,一樣注意virtual關鍵字在pkgfile中無效。
下面是一個可以被tolua解析的pkgfile,例:
class Point {
static int n; // represents the total number of created Points
static int get_n(); // static method
double x; // represents the x coordinate
double y; // represents the y coordinate
static char* className (void); // returns the name of the class
Point (void); // constructor 1
Point (double px, double py); // constructor 2
~Point (void); // destructor
Point add (Point& other); // add points, returning another one
};
class ColorPoint : public Color {
int red; // red color component [0 - 255]
int green; // green color component [0 - 255]
int blue; // blue color component [0 - 255]
ColorPoint (double px, double py, int r, int g, int b);
};
導入lua後,咱們能夠用如下的例子測試:
p1 = Point:new(0.0,1.0)
p2 = ColorPoint:new(1.5,2.2,0,0,255)
print(Point.n) -- would print 2
print(Point:get_n()) -- would also print 2
p3 = p1:add(p2)
local p4 = ColorPoint()
print(p3.x,p3.y) -- would print 1.5 and 3.2
print(p2.red,p2.green,p2.blue) -- would print 0, 0, and 255
p1:delete() -- call destructor
p2:delete() -- call destructor
注意:咱們僅僅可以delete咱們本身建立的對象,p3將會被自動回收,咱們不可以delete它。
Tolua++擴展:須要注意p4是直接調用類名建立的,這種方式和調用new_local方法功能是同樣的,當不適用這個對象時,這個對象能夠被垃圾回收器自動回收。因此它也不該該手動delete。對於在pkg文件中聲明的構造函數,在lua中這個類都會有三個方法:new,new_local,.call回調與之對應。
固然咱們僅僅須要指定那些咱們須要導入到lua中的方法和成員。可是有時候咱們也須要聲明一個沒有任何方法和成員的類,這樣作的目的是不打斷繼承鏈。
從tolua++ 1.0.5開始,可使用一個tolua_outside關鍵字指定一個正規函數做爲一個類的方法或者靜態方法,例:
/////////////// position.h:
typedef struct {
int x;
int y;
} Position;
Position* position_create();
void position_set(Position* pos, int x, int y);
/////////////// position.pkg:
struct Position {
int x;
int y;
static tolua_outside Position* position_create @ create();
tolua_outside void position_set @ set(int x, int y);
};
--------------- position.lua
local pos = Position:create()
pos:set(10, 10)
注意,在position_set方法中調用了一個position * 做爲其第一個參數,這個參數在使用tolua_outside聲明時將會被省略。
注意,咱們不能命名爲new或者new_local方法,以及不能做爲重載操做符,不然將會返回行爲未定義。
Tolua自動綁定下面的二元操做符:
operator+ operator- operator* operator/
operator< operator>= operator== operator[]
對於這些關聯操做符,tolua自動將返回的0值轉換成nil,因此在C中的false將轉變成lua中的false。
用上面的代碼舉一個例子,替換它的一個行爲:
Point add (Point& other); // add points, returning another one
we had:
Point operator+ (Point& other); // add points, returning another one
這樣在lua中咱們就能簡寫成:
p3 = p1 + p2
索引操做符(operator[])在只有一個數字參數時也能夠導入到亂中。這種狀況下,tolua支持返回一個引用或者一個基本類型。假如返回一個引用,在lua中,程序員便可以獲取也能夠設置它的值。假如返回一個非引用,程序員則只能獲取它的值。舉一個例子來講明,假如咱們有一個vector的類,以及綁定了下面的操做符:
double& operator[] (int index);
在這種狀況下,在lua中,咱們能夠這樣使用:
value = myVector[i] and myVector[i] = value
假如咱們按以下方式綁定操做符:
在lua中我就只能這樣使用:
value = myVector[i]
釋放函數(不是class成員)的函數重載不支持。
Tolua++擴展:從版本1.0.90開始支持轉換操做符,例:
/////////////// node.h
// a class that holds a value that can be of type int, double, string or Object*
class Node { // tolua_export
private:
union {
int int_value;
double double_value;
string string_value;
Object* object_value;
};
// tolua_begin
public:
enum Type {
T_INT,
T_DOUBLE,
T_STRING,
T_OBJECT,
T_MAX,
};
Type get_type();
operator int();
operator double();
operator string();
operator Object*();
};
// tolua_end
Tolua++將會生成轉換對象Node調用操做符的代碼(使用C++ static_cast),並把在類中以「.typename」形式註冊他們。例:
-- node.lua
local node = list.get_node("some_node") -- returns a Node object
if node.get_type() == Node.T_STRING then
print("node is "..node[".string"]())
elseif node.get_type() == Node.T_OBJECT then
local object = node[".Object*"]()
object:method()
end
Tolua++從1.0.6版本開始支持聲明類屬性,使用關鍵字tolua_property, 一個看起來像域的屬性,可是其值是同調用類方法獲取的。例:
/////////////// label.h
class Label {
public:
string get_name();
void set_name(string p_name);
Widget* get_parent();
};
/////////////// label.pkg
class Label {
tolua_property string name;
tolua_readonly tolua_property Widget* parent;
};
--------------- label.lua
local label = Label()
label.name = "hello"
print(label.name)
label.parent:show()
一個屬性能夠有不一樣的類型,這些類型決定了如何設置和獲取它的值。Tolua++提供了3中不一樣的嵌入類型。
Default類型,默認狀況下,訪問用名字訪問這個屬性時將會調用其get_name 和set_name方法。
qt 類型將會使用name和setNmae方法。
overload 類型,將會都用name方法,只不過這個方法被重載了兩個函數,獲取函數爲:'string name(void); 設置函數爲:'void name(string);
這個屬性的類型能夠加在tolua_property關鍵字的後面,例:
tolua_property__qt string name;
當沒有類型指定時,默認使用default類型,可是這是能夠被改變的(見下文)
這默認的屬性類型可使用宏'TOLUA_PROPERTY_TYPE'改變,這個宏將會在其調用爲止改變屬性類型,直到遇到宏所在位置的塊結束符。例:
TOLUA_PROPERTY_TYPE(default); // default type for the 'global' scope
namespace GUI {
class Point {
tolua_property int x; // will use get_x/set_x
tolua_property int y; // will use get_y/set_y
};
TOLUA_PROPERTY_TYPE(qt); // changes default type to 'qt' for the rest of the 'GUI' namespace
class Label {
tolua_property string name; // will use name/setName
};
};
class Sprite {
tolua_property GUI::Point position; // will use get_position/set_position
tolua_property__overload string name; // will use name/name
};
自定義屬性類型能夠經過重定義函數get_property_methods_hook(細節見自定義tolua++章節)來增長。這個函數接受屬性類型和名字,而且返回setter 和 getter函數名字。例:
/////////////// custom.lua
function get_property_methods_hook(ptype, name)
if ptype == "hungarian_string" then
return "sGet"..name, "Set"..name
end
if ptype == "hungarian_int" then
return "iGet"..name, "Set"..name
end
-- etc
end
/////////////// label.pkg
class Label {
tolua_property__hungarian_string string Name; // uses 'sGetName' and 'SetName'
tolua_property__hungarian_int string Type; // uses 'iGetType' and 'SetType'
};
Tolua++新增功能中支持模板類,使用指令TOLUA_TEMPLATE_BIND,例:
class vector {
TOLUA_TEMPLATE_BIND(T, int, string, Vector3D, double)
void clear();
int size() const;
const T& operator[](int index) const;
T& operator[](int index);
void push_back(T val);
vector();
~vector();
};
這個TOLUA_TEMPLATE_BIND指令,必須在類聲明的一開始就使用,不然它將會被忽略。上面代碼將會建立4個vector類。每個在TOLUA_TEMPLATE_BIND參數中指定的類型都將會體會宏T(在TOLUA_TEMPLATE_BIND中的第一個參數)。所以,函數operator[], &operator[] 和 push_back 將會有不一樣的標識在不一樣的對象版本中。在C++中一個對象將會使用vector<type> 聲明,在lua中對應表名是vector_type_。因此lua中的代碼能夠這樣寫:
string_vector = vector_string_:new_local()
string_vector:push_back("hello")
string_vector:push_back("world")
print(string_vector[0].." "..string_vector[1])
一樣的,一個模板類可能有多個宏,同時它也多是從其餘模板類繼承而來,例:
class hash_map : public map<K,V> {
TOLUA_TEMPLATE_BIND(K V, int string, string vector<double>)
V get_element(K key);
void set_element(K key, V value);
hash_map();
~hash_map();
};
在這個例子中,一個對象有其餘模板做爲其類型,因此它的聲明爲:hash_map<string,vector<double>>, 然而它在lua中對應的表爲:hash_map_string_vector_double___(在類型重命名章節中有一個更好的方法訪問這些對象)。
注意,因爲定義某些模板類的複雜性,你應該關心如何聲明它們。例如,你建立了類型(hash_map<string,vector<double> >)建立了一個對象,而後適用這個類型(hash_map<string, vector<double> >)聲明一個變量(注意這個類型在string和vector之間多了一個空格),這個變量的類型沒法認證的,無效的。比較好的方法是聲明一個typedef,而且每個類型都適用它(這是C語言的經常使用作法)。咱們用上面的vector舉個例子:
typedef vector VectorInt;
VectorInt variable;