当前位置: 首页 > 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…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

九天毕昇深度学习平台 | 如何安装库?

pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子&#xff1a; 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...