• 面向对象程序设计关于Lua的初识之类


    一些面向对象的语言中提供了类的概念,作为创建对象的模板。在这些语言里,对象是类的实例。 Lua 不存在类的概念,每个对象定义他自己的行为并拥有自己的形状(shape)。然而,依据基于原型(prototype)的语言比如 Self 和 NewtonScript,在 Lua中仿效类的概念并不难。在这些语言中,对象没有类。相反,每个对象都有一个 prototype(原型),当调用不属于对象的某些操作时,会最先会到 prototype 中查找这些操作。在这类语言中实现类(class)的机制,我们创建一个对象,作为其它对象的原型即可(原型对象为类,其它对象为类的 instance)。类与 prototype 的工作机制相同,都是定义了特定对象的行为。在 Lua 中, 使用前面章节我们介绍过的继承的思想,很容易实现 prototypes.更明确的来说,如果我们有两个对象 a 和 b,我们想让 b 作为 a 的 prototype 只需要:

    setmetatable(a, {__index = b})
    
    • 1

    这样,对象 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    当我们调用 Account:new 时, self 等于 Account;因此我们可以直接使用 Account取代 self。然而,使用 self 在我们下一节介绍类继承时更合适)。有了这段代码之后,当我们创建一个新的账号并且掉用一个方法的时候,有什么发生呢?

    a=Account:new()
    a:deposit(100)
    print(a.blance)
    
    • 1
    • 2
    • 3

    输出结果:

    100
    
    • 1

    也就是说, Lua 传递 a 作为 self 参数调用原始的 deposit 函数。所以,新的账号对象从 Account 继承了 deposit 方法。使用同样的机制,可以从 Account 继承所有的域。继承机制不仅对方法有效,对表中所有的域都有效。所以,一个类不仅提供方法,也提供了他的实例的成员的默认值。记住:在我们第一个 Account 定义中,我们提供了成员 balance默认值为 0,所以,如果我们创建一个新的账号而没有提供 balance 的初始值,他将继承
    默认值:

    b=Account:new()
    print(b.blance)
    
    • 1
    • 2

    输出结果:

    0
    
    • 1

    当我们调用 b 的 deposit 方法时,实际等价于:

    b.balance = b.balance + v
    
    • 1

    (因为 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表的原表 
    
    • 1
    • 2
    • 3

    这时候我就出现了疑惑:既然说把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封装起来:
    在这里插入图片描述

  • 相关阅读:
    U-boot(二):主Makefile
    消息队列一|从秒杀活动开始聊起消息队列
    事件处理:SpringBoot+Kafka
    搜索接口搜索“苏州协同创新智能科技时”超时调优
    java[线程]volatile为什么不能保证原子性
    C++——电话号码的字母组合问题
    ubuntu20.0安装 java并配置环境
    【软件工程】期末重点
    3、Pinpoint-Agent端注册服务到Server端
    Jenkins与DevOps持续交付详解
  • 原文地址:https://blog.csdn.net/qq_44918090/article/details/126518091