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
相关推荐
麻瓜code11 小时前
秒杀优化三连:Lua + 阻塞队列 + Redis Stream,响应从 3.4 秒到毫秒级
redis·junit·lua
努力努力再努力wz11 小时前
【Lua 入门系列】Lua 函数深入理解:函数对象、多返回值、可变参数、闭包、递归与尾调用优化
开发语言·lua
hey you~15 小时前
云呼叫中心坐席自动分配实战:ACD 策略、Redis+Lua 实现与排查清单
数据库·redis·lua·云呼叫中心·acd·坐席分配·坐席状态机
我不会起名字32216 小时前
Redis pipeline 用了反而更慢:3 类误用与正确的批量姿势
redis·pipeline·lua·rtt·批量
努力努力再努力wz2 天前
【Lua入门系列】从 C++ 迭代器到 Lua 迭代器:一文深入理解 Lua 有状态以及无状态迭代器与泛型for、闭包、ipairs、pairs 和 next
开发语言·c++·lua
屈冠成3 天前
ShopXO商城系统测试报告
开发语言·spring·maven·lua
Wang's Blog3 天前
Java 项目实战: 交友项目 - 用户体系集成:根据环信id查询用户详情
java·lua·交友
努力努力再努力wz3 天前
【Lua 入门系列】从顺序执行到分支与循环:一文理解 Lua 控制结构、作用域与跳转规则
junit·单元测试·lua
huoyueyi3 天前
《融天AI-APP从0到1开发实录》
开发语言·lua
努力努力再努力wz4 天前
【Lua入门系列】从动态类型到变量作用域:彻底理解 local、全局变量与跨文件访问
开发语言·junit·lua