Lua如何像C++一样面向对象,从问题出现到解决,逐步了解为什么lua需要实现类
admin
2024-03-29 09:04:00
0

本文从以下几点分析逐步学习lua面向对象编程思想
1.怎么解除对象间的依赖关系
2.lua中的语法糖 ’ : ’
3.lua中类的概念
4.lua中的单继承怎么实现
5.lua中的多继承怎么实现

在多继承之前的内容,都很好理解
学习建议:以下所有代码皆可运行,将所有代码都实现一遍。

先展示问题所在,将test1赋值给tt ,但test1释放后(赋值nil可以理解为舍弃), 就会出错

-- 
test1 = {val = 10}
function test1.fun()test1.val = test1.val - 10print(test1.val)
end
tt = test1
-- test1 = nil -- 如果把这句开启 就会出错
-- 因为test1已经复制nil了,但tt.fun仍会调用它
tt.fun()

以下这种方式,多传一个参数,就能解决上边的问题

test1 = {val = 10}
function test1.fun(self) self.val = self.val + 20print(self.val)
end
tt = test1
test1 = nil	//就算赋值nil也不影响。
tt.fun(tt)

到这里,是不是觉得这个self功能其实很像C++中的this指针,就是将自己本身传递进去,lua中有一个语法糖’ : ’ 可以实现避免显式的写出self对象。

比如上边是 tt.fun(tt), 可以通过tt : fun(), 从而省去tt的传参

test1 = {val = 10}
function test1:fun()self.val = self.val + 10print("self:"..self.val) -- 如果把.. 换成, 相当于一个'\t'
endtt = test1
test1 = nil
tt:fun() 

是不是越来越有对象的感觉了。

lua中类的概念 : 我们需要实现一个类, 然后通过这个类来初始化一个对象
lua中面向对象的编程思想最重要的就是, 关于元表的设计,以及元方法(__index)的设计
比如 setmetatable(o, self) , self就是o的元表, 然后再给self设置元方法。
在下边的代码中 new() 函数相当于返回了一个我们需要的对象,关于这个对象所具有的功能,是封装在acount中的,所以我们可以把acount当作类。

local acount = {val = 10}
function acount:new(o)o = o or {}setmetatable(o, self)self.__index = selfreturn o
endfunction acount:display()self.val = self.val + 200print(self.val)
endlocal a = acount:new{val = 0}  -- a 就相当于 acount类的一个对象
--这里改成local a = acount:new() 看一下输出结果
--lua中当传参是一个表的时候可以省略 ()a:display() --等价a.display(a) -- 我这里是给了初始表 {val = 0},-- 若没有给初始表,比如上边换成acount:new(),则a本来是没有val对象的,a.val 就相当于 getmetatable(a).__index(val) 才能得到val --第一次调用display时,self.val 就是 a.val 尽管是去acount中获取的val,但是因为调用了a.val,就相当于在a中添加了一个新的字段val,当第二次调用display时,就不会去acout中寻找val字段了,而是直接用a对象自己的val

lua中的单继承实现
简单分析流程:先创建父类acount, 子类acount_son是通过acount:new()获得的

再通过acount_son:new () 返回的就是子类acount_son的一个对象

下边的代码中还实现了,在子类acount_son中重写父类acount的display方法。

local acount = {val = 10}
function acount:new(o)o = o or {}setmetatable(o, self)self.__index = selfreturn o
endfunction acount:display()self.val = self.val + 100print(self.val)
endacount_son = acount:new()
function acount_son:display()   -- 相当于类中的函数重写 self.val = self.val + 666print(self.val)
endins = acount_son:new()
ins:display() 
--  可以分析一下,ins.val第一次是没有的,先去acount_son再去acount找的
-- 同样ins.display也是一样, 但如过在acount_son中重写了display函数,就相当于实现了重写的效果

lua中的多重继承实现
简单流程分析: 通过上边的演示,我们已经知道了lua的面向对象实质上就是通过__index元方法实现的, 只是对于单继承,直接是self.__index = self,
而多继承中,不能直接 =self ,而是用一个函数,来遍历所继承的所有父类中的方法。

其实不用想的太复杂,多继承和单继承的本质区别就是

setmetatable(c, {__index = function(t,k) return search(k, parentlist) end})

在子类继承父类的时候(c继承CA,CB),不再是像单继承一样self.__index = self了
还有一个关键的细节点, c是子类,我们需要用c返回一个对象**,和单继承返回对象一样**,所以需要实现c:new() ,发现没有,单继承和多继承的区别就在于继承父类的时候__index的设置不同,但生成对象都是一样的方式

local function search(k, parentlist) for i = 1, #parentlist dolocal fun = parentlist[i][k]if fun thenreturn funendend
endfunction createclass(...)local parentlist = {...}local c = {}setmetatable(c, {__index = function(t,k) return search(k, parentlist) end})function c:new(o)o = o or {}setmetatable(o, self)self.__index = selfreturn oend-- 返回新的类return c
end-- 简单类CAlocal CA = {}
function CA:new(o) o = o or {}setmetatable(o, self)self.__index = selfreturn o
endfunction CA:SetName(strName) self.name = strName
end-- 简单类CB
local CB = {}
function CB:new(o) o = o or {}setmetatable(o, self)self.__index = self return o
endfunction CB:GetName()return self.name
end--创建一个c类, 它的父类是CA 和 CB 
local c = createclass(CA, CB) --使用c类创建一个实例对象
local objectc = c:new{name = "jj"} --设置objectc的新名字
objectc:SetName("dashuaigejj")
local newName = objectc:GetName()
print(newName)

相关内容

热门资讯

linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
C++ 机房预约系统(六):学... 8、 学生模块 8.1 学生子菜单、登录和注销 实现步骤: 在Student.cpp的...
A.机器学习入门算法(三):基... 机器学习算法(三):K近邻(k-nearest neigh...
数字温湿度传感器DHT11模块... 模块实例https://blog.csdn.net/qq_38393591/article/deta...
有限元三角形单元的等效节点力 文章目录前言一、重新复习一下有限元三角形单元的理论1、三角形单元的形函数(Nÿ...
Redis 所有支持的数据结构... Redis 是一种开源的基于键值对存储的 NoSQL 数据库,支持多种数据结构。以下是...
win下pytorch安装—c... 安装目录一、cuda安装1.1、cuda版本选择1.2、下载安装二、cudnn安装三、pytorch...
MySQL基础-多表查询 文章目录MySQL基础-多表查询一、案例及引入1、基础概念2、笛卡尔积的理解二、多表查询的分类1、等...
keil调试专题篇 调试的前提是需要连接调试器比如STLINK。 然后点击菜单或者快捷图标均可进入调试模式。 如果前面...
MATLAB | 全网最详细网... 一篇超超超长,超超超全面网络图绘制教程,本篇基本能讲清楚所有绘制要点&#...
IHome主页 - 让你的浏览... 随着互联网的发展,人们越来越离不开浏览器了。每天上班、学习、娱乐,浏览器...
TCP 协议 一、TCP 协议概念 TCP即传输控制协议(Transmission Control ...
营业执照的经营范围有哪些 营业执照的经营范围有哪些 经营范围是指企业可以从事的生产经营与服务项目,是进行公司注册...
C++ 可变体(variant... 一、可变体(variant) 基础用法 Union的问题: 无法知道当前使用的类型是什...
血压计语音芯片,电子医疗设备声... 语音电子血压计是带有语音提示功能的电子血压计,测量前至测量结果全程语音播报࿰...
MySQL OCP888题解0... 文章目录1、原题1.1、英文原题1.2、答案2、题目解析2.1、题干解析2.2、选项解析3、知识点3...
【2023-Pytorch-检... (肆十二想说的一些话)Yolo这个系列我们已经更新了大概一年的时间,现在基本的流程也走走通了,包含数...
实战项目:保险行业用户分类 这里写目录标题1、项目介绍1.1 行业背景1.2 数据介绍2、代码实现导入数据探索数据处理列标签名异...
记录--我在前端干工地(thr... 这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前段时间接触了Th...
43 openEuler搭建A... 文章目录43 openEuler搭建Apache服务器-配置文件说明和管理模块43.1 配置文件说明...