有时我们会把C++类导入到lua,这样方便在lua里面对C++类进行操作,这在游戏编程里面经常使用,本文只是简单介绍一种实现。
1. lua里面面向对象的实现
在lua里面,我们可以这样操作表,如下:
Account = {balance = 0}
function Account:withdraw (v)
self.balance = self.balance - v
end
在这里,我们定义了一个table并且有一个withdraw的函数,我们可以这样使用
a = Account
a:withdraw(100)
这样就跟C++的类形式一样了。但是在lua里面没有类的概念,但是每个对象都有一个prototype(原型),当调用不属于对象的某些操作时,会最先会到prototype中查找这些操作。所以如果我们又两个对象a和b,如果我们把b作为a的prototype,我们就实现了最基本的继承。在lua中只需如下实现
setmetatable(a, {__index = b})
这样a调用任何不存在的成员都会到对象b里面去查找。在这里我们使用了__index metamethod,至于什么是metatable和metamethod lua相关文档有详细说明。(另外特别推荐programming in lua这本书,里面几乎全部介绍了这些知识)
2. C++类在lua中的表现形式
在lua中,我们假设C++类的操作形式如下,假设有一个类A
obj = A:new()
obj:dosomething()
obj:delete()
这里我们没考虑成员变量的操作,因为对于我们来说只是对成员函数进行操作,而且考虑到封装原则不建议对类成员变量进行直接操作,如果要操作我们会在类里面定义相关的成员函数。
3. 设计思想
参考上面的表现形式,我们会把A设定成一个metatable,然后把相关函数与它关联, 也就是把new等函数通过lua_pushfunction使其作为改metatable的函数。而对于obj来说,他是一个A的实例,我们会把它的指针传给lua供lua使用,而这个指针值在lua里面就是用userdata来表示。由于只涉及到函数的操作,所以我们会把metatable的__index与相关处理函数进行关联。
另外,假设A继承于类B,而obj为A的实例,那么obj的metatable为A的metatable,而A的metatable的metatable为B的metatable,这样就保证了继承性。我们通过obj调用函数,obj首先会在A里面查找,如果A里面没有,A会在B里面进行查找。
基于上面的思路,我们首先定义函数:
int reg_type(lua_State *L, const