当前位置: 首页 > news >正文

【Lua学习笔记】Lua进阶——Table(4)继承,封装,多态

在这里插入图片描述

文章目录

  • 封装
  • 继承
  • 多态


封装

// 定义基类
Object = {}//由于表的特性,该句就相当于定义基类变量
Object.id =1//该句相当于定义方法,Object可以视为定义的对象,Test可以视为方法名
//我们知道Object是一个表,但是抽象地看,请把Object看着面向对象中的 “对象”
function Object:Test()print(self.id)
end
// 以上语句等同于:
// public class Object{int id=1;void Test(Object obj)print(obj.id);
}//定义一个new方法,用于创建这个基类的对象
function Object:new()//定义空表obj,用面向对象比喻相当于new了一个空对象local obj = {}//绑定元表,将元表看作一个基类self.__index = selfsetmetatable(obj, self)//返回空对象return obj
endlocal Car = Object:new()  //实际是将new出的空对象return给外部定义的Car
// 以上语句等同于:
// Object Car = new Object();// 由于Car实际上是空的table,所以访问Car其实是通过__index访问基类中的索引
// 相当于虽然没有定义Car内的变量,但初始化时继承基类的值作为了初始值
print(Car.id) --1,来自元表// 同样的,Car实际使用了__index基类提供的方法
// 但是由于入参是self,此处就是Car,print(Car.id),最终还是访问了基类__index找到的Object.id
Car:Test() --1,来自元表// 定义Car中的变量
Car.id = 2
// 现在Car表中有了索引id,那么就能找到这个索引,所以输出为2
Car:Test() --2,来自子表

现在我们可以像面向对象一样,new一个对应基类的对象了。但是这里的new也不完全相似与面向对象的new,例如我们可以这样做:

Car.name = "a"
print(Car.name)
输出:
a

我们在封装Object类的时候可完全没有name这个索引,而在Lua中我们new了一个新对象,还能新加入一些变量和方法,这些特性明显是继承了父类的子类才有的。算不上坏处,不过我们想要完全实现封装还能加以限制:

//定义一个垃圾列表,将添加到子类的垃圾都丢进去
garbage={}//定义一个new方法,用于创建这个基类的对象
function Object:new()//定义空表obj,用面向对象比喻相当于new了一个空对象local obj = {}// 禁止子类的添加self.__newindex = garbage//绑定元表,将元表看作一个基类self.__index = selfsetmetatable(obj, self)//返回空对象return obj
end
local Car = Object:new()
Car.name = "a"
print(Car.name)输出:
nil

现在我们确实实现封装了,既能访问基类的方法和变量,又能阻止新加的其他东西,但是还得把垃圾及时清理,这点我们将在后文垃圾回收中讲解。


继承

面向对象重要的特性之继承,光new一个新对象无法满足全部需要,我们想要重写父类的一些方法而非直接使用它们,就需要继承。

观察上面的Object:new()代码,其实我们如果想用进行继承,其实只需要在上面改改即可

Object = {}
Object.id = 1;
function Object:Test()print(self.id)
end//换种方式,如果我们不return的话,想要返回这个值,可以直接把它丢进全局表中
function Object:subClass(className)_G[className] = {}self.__index = selfsetmetatable(_G[className], self)
end
Object:subClass("Cat")
print(Cat.id)
输出:
1

继承比封装还要简单一点,其实它和我们第一次定义的封装是一模一样的,只是换了种方式来实现。

// new一个Cat类的对象
local WhiteCat = Cat:new()
print(WhiteCat.id) -- 1
function Object:Test()print("我是基类")
endfunction Object:new()local obj = {}self.__newindex = garbageself.__index = selfsetmetatable(obj, self)return obj
endfunction Object:subClass(className)_G[className] = {}self.__index = selfsetmetatable(_G[className], self)
end//Cat继承基类
Object:subClass("Cat")
//new一个Cat类的对象WhiteCat
local WhiteCat = Cat:new()
WhiteCat:Test()  -- 我是基类// 重写Test方法(其实只是新写了一个放在Cat表里被调用,更像重载?)
function Cat:Test()print("我是猫类")
end
WhiteCat:Test()  --我是猫类//想要重写Cat的Test方法?不好意思我已经用__newindex封装好了
//白猫是个对象,而不是Cat这个类,它不应该重写方法
//下面重写的方法会被丢到garbage里
function WhiteCat:Test()print("我是白猫")
end
WhiteCat:Test() --我是猫类
garbage:Test() --我是白猫

如果看不明白,建议重学Table,元表以及面向对象


多态

多态就是对于一个父类的相同方法,子类可以执行不同的逻辑。实现多态我们可以怎么做?

  1. 重写和重载方法
  2. 实现接口
  3. 实现抽象类和抽象方法

如果重写应当是这样:

function Object:Test()print("我是基类")
end
Object:subClass("Cat")
Object:subClass("Dog")
function Cat:Test()print("我是猫类")
end
function Dog:Test()print("我是狗?")
end

重写固然可以实现,问题在于继承了父类之后的重写是无法保留父类的同名方法的,那我想要访问父类的方法怎么办?

别忘了我们的类其实是个table,我直接把父类存进去,然后要使用的时候访问不就行了吗?反正又没有面向对象语法限制。

function Object:subClass(className)_G[className] = {}local obj = _G[className]self.__index = self// 直接把父类表存进子类的baseobj.base = selfsetmetatable(obj , self)
endfunction Dog:Test()print("我是狗?")
end
Dog:Test()
Dog.base:Test()输出:
我是狗?
我是基类function Dog:Test()// 如果想在继承了父类的方法的基础之上重写self.base:Test()print("我是狗?")
endDog:Test() --我是基类 我是狗?

注意,如果我们直接用的父类方法,在调用父类的时候应当避免不同的类共享全局变量:

Object = {}
Object.id = 1;
function Object:Test()self.id = self.id + 1print(self.id)
endObject:subClass("Cat")
function Cat:Test()self.base:Test()print("我是猫类")
end
Object:subClass("Dog")
function Dog:Test()self.base:Test()print("我是狗?")
end输出:
2
我是猫类
3
我是狗?

原因也很简单,table内存放了父类的table,我们直接调用父类的Test方法,那么self.id每次调用都会加一。两个table中的父类是同一个地址,而Object:Test()这个方法中每次传入给self的都是这个xxx.base,也就是这个父类table本身,所以self.id增加的是父类中的id,作为一个全局变量,它自然是不断增加的。

那么我们想让子类既能在继承Object:Test()这个父类方法基础之上重写,又想使得self.id改变的self是我们使用方法的那个子类table,那么就应当这样写:

Object = {}
Object.id = 1;
function Object:Test()self.id = self.id + 1print(self.id)
endObject:subClass("Cat")
function Cat:Test()// 手动地传入参数,因为冒号传入给self的是base// 因此需要手动地改变传入的参数的值self.base.Test(self)print("我是猫类")
end
Cat:Test()输出:
2
我是猫类

重载应该是最简单的多态方法,只需要改变函数的入参数量就行了

至于接口和抽象类,lua本身的函数就可以重写,抽象性还是很强的。而接口我们应当可以访问另一个table结构来实现,例如self.base应当就能视为一种接口,当然这些只是我的想法,目前还没学习到。

相关文章:

【Lua学习笔记】Lua进阶——Table(4)继承,封装,多态

文章目录 封装继承多态 封装 // 定义基类 Object {}//由于表的特性,该句就相当于定义基类变量 Object.id 1//该句相当于定义方法,Object可以视为定义的对象,Test可以视为方法名 //我们知道Object是一个表,但是抽象地看&#xff…...

安全性证明(四)Practical Identity-Based Encryption Without Random Oracles

...

Linux中常用的指令

ls ls [选项] [目录或文件] 功能:对于目录,列出该目录下所有的子目录和文件;对于文件,列出该文件的文件名和其他属性 常用选项: -a:列出目录下的所有文件,包括以.开头的隐藏文件 -l:列出文件的详细信息。…...

【java】【面对对象高级4】内部类、枚举、泛型

目录 1、内部类 1.1 成员内部类【了解】 1.1.1 定义 1.1.2 扩展变量 1.2 静态内部类【了解】 1.2.1 定义 1.2.2 扩展变量 1.3 局部内部类【了解】 1.4 匿名内部类【重点】 1.4.1 定义 1.4.1.1 常规写法 1.4.1.2 匿名内部类改造 1.4.2 匿名内部类的常见使用场景 1.4.2…...

Python的用处到底是什么?(三)

11. 数据库操作:Python的库,如sqlite3和SQLAlchemy,可以连接和操作各种类型的数据库。 Python提供了一些库和工具,如sqlite3和SQLAlchemy,用于连接和操作各种类型的数据库。以下是关于这两个库的详细解释:…...

【Nodejs】Express基本使用

Express 中文网 基于 Node.js 平台,快速、开放、极简的 web 开发框架。 1.Express的安装方式 Express的安装可直接使用npm包管理器上的项目,在安装npm之前可先安装淘宝镜像: npm install -g cnpm --registryhttps://registry.npmmirror.com/…...

k8s集群安装v1.20.9

参考网上资料并将异常问题解决,经测试可正常安装集群。 1.我的环境准备 本人使用vmware pro 17新建三个centos7虚拟机,每个2cpu,20GB磁盘存储,内存2GB,其中主节点的内存3GB,可使用外网. 2.所有节点安装D…...

Staples Drop Ship EDI 需求分析

Staples 是一家美国零售公司,总部位于马萨诸塞州弗拉明汉,主要提供支持工作和学习的产品和服务。该公司于 1986 年在马萨诸塞州布莱顿开设了第一家门店。到 1996 年,该公司已跻身《财富》世界 500 强,后来又收购了办公用品公司 Qu…...

模型调参及优化

调参 调权重参数,偏置参数 训练数据集用来训练参数w,b 调超参数 验证数据集用来选择超参数学习率lr,隐藏层大小等 如何调参 当泛化误差和训练误差都没有降下去说明欠拟合;当训练误差降下去,但泛化误差出现上升形式&…...

多数据源数据转换和同步的ETL工具推荐

有许多支持多数据源数据转换和同步的ETL工具可供选择。以下是一些常见的ETL工具和它们支持多数据源数据转换和同步的特点: Apache NiFi:Apache NiFi是一个开源的ETL工具,支持多种数据源的连接,包括文件系统、数据库、消息队列、网…...

配置 gitlab https 访问

文章目录 1. 备份2. 生成SSL证书3. 配置文件4. 重启5. 访问 1. 备份 docker exec -ti gitlab-ce gitlab-rake gitlab:backup:create2. 生成SSL证书 yum install openssl openssl-devel -y mkdir /data/gitlab/config/ssl ; cd /data/gitlab/config/ssl### 生成证书 openssl…...

Kepware Modbus驱动简介

1. Modbus驱动能够解决什么问题? 它是Modbus设备驱动的集合,为用户提供一种方便快捷的Modbus设备数采解决方案。 只需要通过简单的配置就可以将常见的例如Modbus TCP/IP Ethernet、RTU Serial 和 ASCII Serial等协议设备无缝连接到 HMI/SCADA、MES/His…...

从零开始学习CTF——CTF是什么

引言: 从2019年10月开始接触CTF,学习了sql注入、文件包含等web知识点,但都是只知道知识点却实用不上,后来在刷CTF题才发现知识点的使用方法,知道在哪里使用,哪里容易出漏洞,可是在挖src漏洞中还…...

为Android构建现代应用——主体结构

创建Screents和ViewModels 在前面的章节中,我们已经分析了OrderNow项目的理论概念和我们将赋予的组织。 在本章中,我们将开始实现初始结构和模板,这将联接每一个应用程序的部分。 首先将添加以下带有各自视图模型的主屏幕: •…...

【shell脚本】shell脚本之日志切割(进阶实战三)

恭喜你,找到宝藏博主了,这里会分享shell的学习整过程。 shell 对于运维来说是必备技能之一,它可以提高很多运维重复工作,提高效率。 shell的专栏,我会详细地讲解shell的基础和使用,以及一些比较常用的she…...

VMLogin和虚拟机里的浏览器有什么区别?

虚拟机(Virtual Machine)指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统。 指纹浏览器,也称防关联浏览器。 简单来说,就是允许在同一台电设备上操作和管理多个平台、多个账号,账…...

unimrcp server的session资源分配与回收

unimrcp使用APR的内存池管理内存,因此,处理函数中一般都会传递一个pool指针,需要内存时,就从pool里分配一块,一般也不需要关心内存的释放。因为,一路呼叫关联一个session,一个session对应一个po…...

【图论】三种中心性 —— 特征向量、katz 和 PageRank

维基百科:在图论和网络分析中,中心性指标为图中相应网络位置的节点分配排名或数值。中心性这一概念最初起源于社交网络分析,因此很多衡量中心性的术语也反映了其社会学背景。 不同中心性指标对 “重要” 的衡量方式不同,因此适用于…...

[sqoop]将hive查询后的数据导入到MySQL

一、知识点 export:将Hive的表导入到mysql叫导出 搜了很多,发现sqoop在hive导出到mysql时 1)不支持where参数对数据进行过滤。 2)不支持指定hive表的方式导出,只能指定Hive目录进行导出。 二、操作 1、在MySQL中建表 creat…...

Linux df、du命令

df:查看文件系统硬盘使用情况 df 命令,用于显示 Linux 系统中各文件系统的硬盘使用情况,包括文件系统所在硬盘分区的总容量、已使用的容量、剩余容量等。 df 命令的基本格式为: [rootlocalhost ~]# df [选项] [目录或文件名] df…...

STM32姿态报警器设计:MPU6050与卡尔曼滤波实战

基于STM32的姿态翻转报警器设计与实现1. 项目概述1.1 系统架构本姿态翻转报警系统采用模块化设计,核心架构由STM32F103RCT6微控制器作为主控单元,通过I2C接口连接MPU6050惯性测量单元(IMU)传感器,实时采集设备的三轴加速度和三轴角速度数据。…...

保姆级避坑指南:Ubuntu系统下Hadoop HA集群搭建,我踩过的那些SSH和配置文件的“坑”

Ubuntu下Hadoop HA集群搭建:那些教科书不会告诉你的实战陷阱 第一次在Ubuntu上搭建Hadoop HA集群时,我天真地以为照着官方文档就能顺利跑起来。直到SSH连接莫名其妙失败、JournalNode权限报错刷屏、ZKFC死活不启动时,才明白为什么有人说大数据…...

STM32CubeMX实战:5分钟搞定RTC定时唤醒低功耗设计(附LED状态检测技巧)

STM32CubeMX实战:RTC定时唤醒与低功耗设计的5个关键技巧 嵌入式开发者经常面临一个挑战:如何在保证设备功能完整的同时,最大限度地延长电池寿命。RTC(实时时钟)定时唤醒技术正是解决这一问题的利器,它能让…...

英飞凌AURIX TC3XX GPIO驱动配置与LED呼吸灯实现

1. 认识AURIX TC3XX的GPIO模块 第一次接触英飞凌AURIX TC3XX系列MCU时,我被它强大的GPIO功能惊艳到了。这不仅仅是一个简单的数字输入输出接口,而是集成了多种高级特性的硬件模块。在实际汽车电子项目中,比如氛围灯控制、状态指示灯等场景&a…...

多模态数字人智能交互平台源码获取方式,支持语音克隆+实时渲染,可商用

温馨提示:文末有资源获取方式最近“龙虾AI”的热度很高,似乎人人都想养一个属于自己的数字员工。但现实是,这类技术对普通用户并不友好:部署需要代码、配置需要专人、调试更是门槛重重。更别提高昂的Token消耗,轻度使用…...

3KW无线充电系统设计:开环控制与闭环控制的MATLAB Simulink仿真模型,采用双边L...

3KW无线充电系统设计(MATLAB simulink仿真模型) 控制方式:开环控制闭环控制 拓扑结构:双边LCC拓扑结构 输入电压:750V 输出电压:400V 传输功率:3KW 最近在折腾一个3KW无线充电系统的仿真项目&am…...

5分钟快速上手!用VeriStand为你的Simulink模型搭建一个简易监控仪表盘

5分钟快速上手!用VeriStand为Simulink模型搭建实时监控仪表盘 在工程仿真领域,能够直观观察模型运行状态并实时调整参数,是提升开发效率的关键。想象一下这样的场景:你刚完成一个BUCK电路的Simulink建模,通过仿真验证了…...

FedMeta: Accelerating Federated Learning with Meta-Learning for Enhanced Privacy and Efficiency

1. FedMeta:当联邦学习遇上元学习 想象一下,你正在训练一个能识别手写数字的AI模型,但数据分散在成千上万个用户的手机里。传统联邦学习就像让每个用户都从头开始训练完整模型,既耗流量又费时间。而FedMeta的聪明之处在于——它让…...

PX4飞控系统深度探索:如何用开源技术打造智能无人机控制大脑

PX4飞控系统深度探索:如何用开源技术打造智能无人机控制大脑 【免费下载链接】PX4-Autopilot PX4 Autopilot Software 项目地址: https://gitcode.com/gh_mirrors/px/PX4-Autopilot 想象一下,你正站在一片开阔的试验场上,手里握着一架…...

深度学习模型压缩:从原理到实践

深度学习模型压缩:从原理到实践 1. 背景与动机 深度学习模型在各种任务上取得了显著的性能提升,但随之而来的是模型规模的不断增长。大型模型虽然性能优异,但也带来了以下问题: 存储需求大:大型模型需要大量存储空间&a…...