Lua教程(十二):面向对象编程
Lua中的table就是一种对象,但是如果直接使用仍然会存在大量的问题,见如下代码:
Account={balance=0} functionAccount.withdraw(v) Account.balance=Account.balance-v end --下面是测试调用函数 Account.withdraw(100.00)
在上面的withdraw函数内部依赖了全局变量Account,一旦该变量发生改变,将会导致withdraw不再能正常的工作,如:
a=Account;Account=nil a.withdraw(100.00) --将会导致访问空nil的错误。
这种行为明显的违反了面向对象封装性和实例独立性。要解决这一问题,我们需要给withdraw函数在添加一个参数self,他等价于Java/C++中的this,见如下修改:
functionAccount.withdraw(self,v) self.balance=self.balance-v end --下面是基于修改后代码的调用: a1=Account;Account=nil a1.withdraw(a1,100.00) --正常工作。
针对上述问题,Lua提供了一种更为便利的语法,即将点(.)替换为冒号(:),这样可以在定义和调用时均隐藏self参数,如:
functionAccount:withdraw(v) self.balance=self.balance-v end --调用代码可改为: a:withdraw(100.00)
1.类:
Lua在语言上并没有提供面向对象的支持,因此想实现该功能,我们只能通过table来模拟,见如下代码及关键性注释:
--[[ 在这段代码中,我们可以将Account视为class的声明,如Java中的: publicclassAccount { publicfloatbalance=0; publicAccount(Accounto); publicvoiddeposite(floatf); } --]] --这里balance是一个公有的成员变量。 Account={balance=0}
--new可以视为构造函数 functionAccount:new(o) o=oor{}--如果参数中没有提供table,则创建一个空的。 --将新对象实例的metatable指向Account表(类),这样就可以将其视为模板了。 setmetatable(o,self) --在将Account的__index字段指向自己,以便新对象在访问Account的函数和字段时,可被直接重定向。 self.__index=self --最后返回构造后的对象实例 returno end
--deposite被视为Account类的公有成员函数 functionAccount:deposit(v) --这里的self表示对象实例本身 self.balance=self.balance+v end
--下面的代码创建两个Account的对象实例
--通过Account的new方法构造基于该类的示例对象。 a=Account:new() --[[ 这里需要具体解释一下,此时由于tablea中并没有deposite字段,因此需要重定向到Account, 同时调用Account的deposite方法。在Account.deposite方法中,由于self(a对象)并没有balance 字段,因此在执行self.balance+v时,也需要重定向访问Account中的balance字段,其缺省值为0。 在得到计算结果后,再将该结果直接赋值给a.balance。此后a对象就拥有了自己的balance字段和值。 下次再调用该方法,balance字段的值将完全来自于a对象,而无需在重定向到Account了。 --]] a:deposit(100.00) print(a.balance)--输出100
b=Account:new() b:deposit(200.00) print(b.balance)--输出200