面向对象程序设计关于Lua的初识之类
Posted 森明帮大于黑虎帮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向对象程序设计关于Lua的初识之类相关的知识,希望对你有一定的参考价值。
一些面向对象的语言中提供了类的概念,作为创建对象的模板。在这些语言里,对象是类的实例。 Lua
不存在类的概念,每个对象定义他自己的行为并拥有自己的形状(shape)
。然而,依据基于原型(prototype)
的语言比如 Self 和 NewtonScript
,在 Lua
中仿效类的概念并不难。在这些语言中,对象没有类。相反,每个对象都有一个 prototype(原型)
,当调用不属于对象的某些操作时,会最先会到 prototype
中查找这些操作。在这类语言中实现类(class)
的机制,我们创建一个对象,作为其它对象的原型即可(原型对象为类,其它对象为类的 instance)。类与 prototype
的工作机制相同,都是定义了特定对象的行为。在 Lua
中, 使用前面章节我们介绍过的继承的思想,很容易实现 prototypes.更明确的来说,如果我们有两个对象 a 和 b,我们想让 b 作为 a 的 prototype 只需要:
setmetatable(a, __index = b)
这样,对象 a 调用任何不存在的成员都会到对象 b 中查找。 术语上,可以将 b 看作类, a 看作对象。
回到前面银行账号的例子上。为了使得新创建的对象拥有和 Account
相似的行为,我们使用__index metamethod
,使新的对象继承 Account
。注意一个小的优化:我们不需要创建一个额外的表作为 account 对象的 metatable;我们可以用 Account表本身作为 metatable:
Account=blance=0
function Account:withdraw(v)
self.blance=self.blance-v
end
function Account:deposit(v)
self.blance=self.blance+v
end
function Account:new(o)
o=o or
setmetatable(o,self)
self.__index=self
return o
end
当我们调用 Account:new
时, self 等于 Account;因此我们可以直接使用 Account取代 self。然而,使用 self
在我们下一节介绍类继承时更合适)。有了这段代码之后,当我们创建一个新的账号并且掉用一个方法的时候,有什么发生呢?
a=Account:new()
a:deposit(100)
print(a.blance)
输出结果:
100
也就是说, Lua 传递 a 作为 self 参数调用原始的 deposit 函数。所以,新的账号对象从 Account 继承了 deposit 方法。使用同样的机制,可以从 Account 继承所有的域。
继承机制不仅对方法有效,对表中所有的域都有效。所以,一个类不仅提供方法,也提供了他的实例的成员的默认值。记住:在我们第一个 Account 定义中,我们提供了成员 balance默认值为 0,所以,如果我们创建一个新的账号而没有提供 balance 的初始值,他将继承
默认值:
b=Account:new()
print(b.blance)
输出结果:
0
当我们调用 b 的 deposit 方法时,实际等价于:
b.balance = b.balance + v
(因为 self 就是 b)。表达式 b.balance 等于 0 并且初始的存款(b.balance)被赋予b.balance。下一次我们访问这个值的时候,不会在涉及到 index metamethod,因为 b 已经存在他自己的 balance 域。
类在面向对象语言中就好象一个模板,通过模板所创建的实例就具有模板中规定的特性。Lua中没有类的概念,每一个对象规定自己的行为,每一个对象就是自己的实例。不过在Lua中模拟“类”并不难,我们可以用继承的概念,使用两个对象,让其中一个对象作为另一个对象的“类”。
在Lua语言中,我们如果有两个对象A和B,要让B成为A的一个原型,只需要:
B.__index = B // 把B表的__index字段仍然设置为B
setmetatable(A,B) // 把B表设置为A表的原表
这时候我就出现了疑惑:既然说把B设置为A的原表,那A没有的属性就可以在B中寻找了呀,设置B.__index是什么东西?
而这个理解是完全错误的,实际上,即使将A的元表设置为B,而且B中也确实有这个成员,返回结果仍然会是nil,原因就是B的__index元方法没有赋值。拥有了元表等于告诉了Lua:在A表找不到数据时,我们有解决方法;而元表中的__index则是告诉Lua:你从我的__index中找去吧。
这个时候son想访问父亲的house变量还是返回一个nil的,所以为了实现功能,我们应该这样改:
OK,这个时候我们就可以实现以B类作为原型的A类对象的实现啦 。可是这又是setmetatable又是要设置__index,弄得很不美观,我们是用java,C++的时候不就是new来new去的吗?
所以我们就可以把它用一个new封装起来:
以上是关于面向对象程序设计关于Lua的初识之类的主要内容,如果未能解决你的问题,请参考以下文章