当前位置 : 主页 > 网络编程 > lua >

Lua面向对象编程

来源:互联网 收集:自由互联 发布时间:2021-06-23
面向对象的三个基本特征 封装:隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别。 继承:使子类具有父类的属性、方法或者重新定义、追加属

面向对象的三个基本特征

  1. 封装:隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别。
  2. 继承:使子类具有父类的属性、方法或者重新定义、追加属性和方法等。
  3. 多态:同以操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类的方法。


Lua中的面向对象

Lua中的表和对象有很多相似性,因此在Lua中可以使用表来实现面向对象。
Lua中类的方法可以通过表+function来模拟

zhangsan = {name = ""}

function zhangsan.setName(self, name)
    self.name = name
end

zhangsan.setName(zhangsan, "张三")
print(zhangsan.name)

--输出:
--张三


类(Class)

上面的例子中,zhangsan对象拥有了属性和方法,但是这个对象却不是通过类来创建的。在大多数面向对象的语言中都提供了类的概念,类在对象创建中扮演了模板的作用。
在Lua中,我们可以使用原型的思想来模拟类。让每一个对象都有一个原型,当对象遇到未知的操作时就在原型中去查找。
如下,为zhangsan指定它的原型Person:

Person = {}
function Person.setName(self, name)
    self.name = name
end

function Person:new(person)
    person = person or {}
    self.__index = self
    setmetatable(person, self)
    return person
end

zhangsan = Person:new()
print(zhangsan.name)

zhangsan:setName("张三")
print(zhangsan.name)

--输出:
--nil
--张三

在上面的代码中,使用了冒号:来操作,如Person:new(person)这样的写法相当于Person.new(Person, person),冒号只是一个语法糖,这个函数中的self即为Person类本身。


继承

在类(Class)的new操作中,self.__index = self,将Person的元方法__index指向了自身,这样做会导致当调用一个方法时,解释器第一时间将会查找Person自身有没有这个方法。这一点和继承很相似。
在继承中,子类可以拥有父类的属性和方法,也可以定义自己的属性和方法。
如果要从一个类中派生一个子类,可以先创建一个从基类继承了所有操作的空类:

Male = Person:new()
Male.sex = "男"

zhangsan = Male:new()
zhangsan:setName("张三")
print(zhangsan.name, zhangsan.sex)

--输出:
--张三    男

Male拥有了Person的new方法,同时通过Male创建的zhangsan拥有Person的setName方法。
在这个过程中,Male = Person:new()会将Male的元表设置为Person,zhangsan = Male:new()则将zhangsan的元表设置为了Male。
当调用zhangsan:setName时,Lua将首先从zhangsan查找setName方法,发现不存在时,则从zhangsan元表Male的元方法__index中(即Male本身)查找,直到在Person中找到该方法。因此,zhangsan不仅有Male的sex属性,还拥有Person的setName方法。
同时,还可以很方便地在Male中重写Person的setName方法,只需要定义一个新方法即可。

function Male:setName(name)
    self.name = "Male:"..name
end

zhangsan = Male:new()
zhangsan:setName("张三")
print(zhangsan.name)

--输出:
--Male:张三

这是由于,在Male中已经有setName方法了,所以解释器不会再去Person中去查找。

网友评论