面向对象程序设计关于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封装起来:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_44918090/article/details/126518091