引言
要將C++中的對象類型映射到Lua中,就不得不要先了解Lua面向對象的機制。在這里,我們先看一下Lua面向對象的實現基礎——metatable,再以此實現C++對象到Lua的映射。
Lua面向對象
不得不先提一下Lua的幾種函數寫法,普通函數有兩種寫法:
如果要將一個普通函數賦給一個表,有如下寫法:
如果函數里面需要引用表的值,有兩種寫法:
其中,第二種寫法就是一種面向對象的寫法了,它隱藏了第一個參數:self。我們還有另一種調用該函數的方式,即通過顯示的傳遞self參數的形式:
至此,看起來有點“面向對象” 的意味了。下面我們通過metatable來實現“繼承”的效果,代碼如下:
注意其中為Base定義的new方法的實現,在其中通過setmetatable來將Base的metatable賦值給傳入的table的metatable。由此實現了“繼承”的效果。
將簡單的C++對象映射到Lua中
其實,所謂把C++對象映射到Lua中,本質上是把一些對特定數據做操作的函數以metatable的形式包裝一下。我們定義如下C++對象:
該類包裝了一下整數的加減法操作,並且內部有個計數,記錄下該類的實例一共做了多少次加減法。C++中類定義好了,要將它映射到Lua中,有這么幾個步驟:1、創建該對象; 2、在Lua中創建一個元表,將C++類中的成員函數映射過去,以便使用Lua的面向對象的語法來操作。首先,我們在Lua中以new這個語義來創建C++中的對象,代碼如下:
先在lua中new一個userdata,然后強轉指針,接着在改指針指向的內存上調用構造函數。在lua中構造好對象后,將該對象關聯元表calculate。
根據上一篇的內容,我們知道,在Lua中注冊函數要這么寫:
我們將其包含入Lua試試,C++代碼與Lua代碼分別如下:
輸出如下:
啊哈,初步成功了。已經將new的語義映射到Lua中了。下面我們一起再將成員函數映射入Lua。包裹成員函數的代碼如下:
有上一篇的基礎,看這個應該非常簡單。在這里,Lua傳進來的第一個參數要是一個Calculate對象,我用#define包裹了一下檢查該對象的語句:
由於要將成員函數與元表關聯起來,所以在打開庫的地方添加一點代碼,並且成員映射函數的時候,要在另一個luaL_Reg結構中。代碼如下:
在這里,我直接將CalculateToString方法映射為__tostring,那么在lua中輸出該對象時,便會自動調用該方法,我們來看看lua的寫法:
輸出結果如下:
是不是很自然?哈哈。其中Calculate的Sub方法,就留給大家自己去實現了。
總結
Lua中所謂面向對象,在調用函數的寫法上,僅僅是將其第一個self參數隱藏傳入函數而已。繼承的特性,則是通過查詢元表所關聯的函數來實現。通過以上,可以看到手工將C++對象映射到Lua中是有點繁瑣的。下一篇,我們一起用工具來幫我們實現這些代碼。