lua面向对象

建议提前学习https://www.runoob.com/lua/lua-metatables.html

面向对象特征

  • 1) 封装:指能够把一个实体的信息、功能、响应都装入一个单独的对象中的特性。
  • 2) 继承:继承的方法允许在不改动原程序的基础上对其进行扩充,这样使得原功能得以保存,而新功能也得以扩展。这有利于减少重复编码,提高软件的开发效率。
  • 3) 多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。
  • 4)抽象:抽象(Abstraction)是简化复杂的现实问题的途径,它可以为具体问题找到最恰当的类定义,并且可以在最恰当的继承级别解释问题。

lua并没有严格的面向对象的语法,我们只是使用表的特性来模拟类。

lua是duck风格,不存在访问性的问题。所以我们这里考虑如下四种概念:

  • 静态变量:属于该类的变量
  • 静态函数:属于该类的函数
  • 成员变量:属于该类对象的变量
  • 成员函数:属于该类对象的函数

一个类是一个元表,表中存储静态变量、静态函数、以及对象的成员函数。

一个对象是一张表,表中存储了成员变量。

如下表:

属于 代码位置 写法
静态变量 元表 .
静态函数 元表 .
成员变量 对象 .
成员函数 对象 元表 :

示例如下:

Lua 复制代码
A = {             -- 类名为 A
    staticVar = 0 -- 静态变量
}
A.__index = A     -- 当做格式即可


function A.StaticFunc()                   -- 静态函数
    print("staticVar is " .. A.staticVar) -- 可以访问静态变量
end

function A:New(number) -- 定义构造函数,使用其它名称也是可以的
    -- self 类似 this 指针
    local obj = {}
    setmetatable(obj, self)     -- 将对象 obj 的元表设置为类 A
    obj.normalVar = number or 0 -- 使用 or 来制定默认值
    return obj
end

function A:NormalMethod()                    -- 成员函数
    print("normalVar is " .. self.normalVar) -- 可以访问成员变量
end

local a1 = A:New(1) -- 调用构造函数来创建对象
local a2 = A:New(2)
a1.normalVar = 10   -- 修改成员变量
a1:NormalMethod()   -- 调用成员函数
a2:NormalMethod()

A:StaticFunc()  -- 通过类名调用静态函数
a1:StaticFunc() -- 通过对象调用静态函数

输出如下:

text 复制代码
normalVar is 10
normalVar is 2
staticVar is 0
staticVar is 0

最后补充一个讨论,调用时这两种写法等价:

Lua 复制代码
a1:NormalMethod()   -- 调用普通方法
a1.NormalMethod(a1) -- 等价于上述写法

但是显然第二种写法危险得多,因为可能第二个a1会拼写错误。

类继承

虽然lua不鼓励大家写继承,但是还是能写的。

对于单继承的情况,将子类的元表设置成基类即可。例如:

Lua 复制代码
setmetatable(B, A) -- B 继承了 A

示例如下:

Lua 复制代码
A = {             -- 基类名为 A
    staticVar = 0 -- 静态变量
}
A.__index = A     -- 当做格式即可


function A.StaticFunc()                   -- 静态函数
    print("staticVar is " .. A.staticVar) -- 可以访问静态变量
end

function A:New(number) -- 定义构造函数,使用其它名称也是可以的
    -- self 类似 this 指针
    local obj = {}
    setmetatable(obj, self)     -- 将对象 obj 的元表设置为类 A
    obj.normalVar = number or 0 -- 使用 or 来制定默认值
    return obj
end

function A:NormalMethod()                    -- 成员函数
    print("normalVar is " .. self.normalVar) -- 可以访问成员变量
end

B = {}             -- 继承类名为 B
B.__index = B      -- 当做格式即可
setmetatable(B, A) -- B 继承了 A


function B:New(number)               -- 定义构造函数,使用其它名称也是可以的
    -- self 类似 this 指针
    local obj = A:New(number)        -- 使用基类的构造函数
    setmetatable(obj, self)          -- 将对象 obj 的元表设置为类 B
    obj.normalVar2 = number + 1 or 0 -- 使用 or 来制定默认值
    return obj
end

function B:NormalMethod2()                     -- 成员函数
    print("normalVar2 is " .. self.normalVar2) -- 可以访问成员变量
end

local b = B:New(1) -- 调用构造函数来创建对象
b.normalVar = 10   -- 修改成员变量
b:NormalMethod()   -- 调用成员函数
b.normalVar2 = 11
b:NormalMethod2()
b.StaticFunc() -- 可以通过派生类对象访问基类的静态函数

输出如下:

text 复制代码
normalVar is 10
normalVar2 is 11
staticVar is 0

覆盖

另外,由于__index寻址的问题,子类的同名函数会覆盖基类的函数。例如:

Lua 复制代码
A = {             -- 基类名为 A
    staticVar = 0 -- 静态变量
}
A.__index = A     -- 当做格式即可


function A:New(number) -- 定义构造函数,使用其它名称也是可以的
    -- self 类似 this 指针
    local obj = {}
    setmetatable(obj, self)     -- 将对象 obj 的元表设置为类 A
    obj.normalVar = number or 0 -- 使用 or 来制定默认值
    return obj
end

function A:NormalMethod()                    -- 成员函数
    print("normalVar is " .. self.normalVar) -- 可以访问成员变量
end

B = {}             -- 继承类名为 B
B.__index = B      -- 当做格式即可
setmetatable(B, A) -- B 继承了 A


function B:New(number)               -- 定义构造函数,使用其它名称也是可以的
    -- self 类似 this 指针
    local obj = A:New(number)        -- 使用基类的构造函数
    setmetatable(obj, self)          -- 将对象 obj 的元表设置为类 B
    obj.normalVar2 = number + 1 or 0 -- 使用 or 来制定默认值
    return obj
end

function B:NormalMethod()                      -- 成员函数
    print("normalVar2 is " .. self.normalVar2) -- 可以访问成员变量
end

local b = B:New(1) -- 调用构造函数来创建对象
b:NormalMethod()   -- 调用成员函数

输出结果为:

text 复制代码
normalVar2 is 2

而不是:

text 复制代码
normalVar is 1
相关推荐
程序员陆通2 天前
如何使用ChatGPT API及Bito插件
开发语言·chatgpt·lua
谷隐凡二2 天前
windows环境下luarocks下载包的使用
开发语言·lua
程序那点事儿3 天前
open-resty 服务安装kafka插件
linux·分布式·nginx·kafka·lua·运维开发·openresty
半夏知半秋8 天前
支持分页的环形队列
java·开发语言·算法·lua·database
执键行天涯9 天前
【JAVA高级】如何使用Redis加锁和解锁(一)、Lua脚本执行原理及流程
java·redis·lua
倘若猫爱上鱼10 天前
Lua中..和...的使用区别
开发语言·lua
丁总学Java14 天前
分布式锁优化之 使用lua脚本改造分布式锁保证判断和删除的原子性(优化之LUA脚本保证删除的原子性)
分布式·lua
Lill_bin17 天前
Lua编程语言简介与应用
开发语言·数据库·缓存·设计模式·性能优化·lua
两水先木示18 天前
【Lua坑】Lua协程coroutine无法正常完整执行问题
开发语言·lua·协程·对象池
合宙Luat20 天前
从边缘到云端,合宙DTU&RTU打造无缝物联网解决方案
嵌入式硬件·物联网·硬件工程·lua