简介

1. lua面向对象编程是基于元表metatable,元方法__index来实现的,具体元表和元方法的介绍

请见Lua的元表metatable及元方法

2. 语法糖

语法糖是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用

举例说明:数组char test[100],如果要访问第11个元素,可以这样写:char c = *(test+10),但是用语法糖的话就简单了,直接char c = test[10],看到没?语法糖就是一些简便写法!

    lua中的语法糖

lua中的函数默认都是有self传递进去的,self相当于C++类中函数的this指针,语法糖会自动给我们传递 self

举例说明:

local a =
{x = 99
}-- 打印函数,注意这里要访问表a中的变量x,必须指明self.x或者a.x,不然会报错
function a:Print()print("function a:test() " ..self.x)
end-- 想调用a的Print()函数,我们可以这样写,注意参数是a,否则调用出错
a.Print(a)-- 也可以这样写,即用:代替. 且不用传入参数a
a:Print()

明显第二种方法更简便

2. lua面向对象的原理(基于元表metatable和元方法__index)

    如果访问了lua表中不存在的元素时,就会触发lua的一套查找机制,也是凭借这个机制,才能够实现面向对象的

举例说明:

test =
{
}-- 访问表test中不存在的变量a
print(test.a)

打印结果:nil

原因很简单:表test中不存在变量a,所以打印为nil,但是如果表test有元表metatable的话,情况就不一样了

元表像是一个备用查找表,假设表A的元表是B,那么在A中找不到的东西就会尝试在B中去找,设置元表的函数如下

    setmetatable(A, B),这样表B就被设置为A的元表,当A中查找不到某个变量时就会到B中进行查找

    举例说明:

-- 表A
A =
{
}-- 表B
B =
{a = 99
}-- 设置表B为表A的元表
setmetatable(A,B)-- 再访问表A中不存在的变量a
print(A.a)

打印结果依然为:nil

why?因为表B 的元方法__index没有赋值。按照笔者的理解,元方法__index是用来确定一个表在被作为元表时的查找方法

我们做如下更改,即对表B的元方法进行赋值

代码如下:

-- 表A
A =
{
}-- 表B
B =
{a = 99
}-- 给表B的元方法__index进行赋值
B.__index = B-- 设置表B为表A的元表
setmetatable(A,B)-- 再访问表A中不存在的变量a
print(A.a)

打印结果:99

查找过程:访问A.a时,表A中没有a这个变量,但是lua发现表A有元表,即表B,于是再到表B中进行查找,但是lua并不是直接在表B中查找变量a,而是调用表B的元方法__index,如果__index为nil,那就会返回nil。如果__index被赋值为一个表(上面的例子就是__index被赋值为表B自己),那么就会到__index指向的那个表(即表B)中进行查询,于是找到了变量a;如果__index被赋值为一个函数,那么查找时就会返回该函数的返回值

代码如下:

-- 表A
A =
{
}-- 表B
B =
{a = 99
}-- 给表B的元方法__index进行赋值,这里赋值为一个函数
B.__index = function(table, key)print("在元表中访问了变量"..key)return 88end-- 设置表B为表A的元表
setmetatable(A,B)-- 再访问表A中不存在的变量a
print(A.a)

打印结果:

在元表中访问了变量a

88

总结元表的查找步骤:

步骤1.在表中查找,如果找到,返回该元素,找不到则继续步骤2

步骤2.判断该表是否有元表,如果没有元表,返回nil,有元表则继续步骤3

步骤3.判断元表有没有__index方法,如果__index方法为nil,则返回nil;如果__index方法是一个表,则重复步骤1、2、3;如果__index方法是一个函数,则调用该函数,并返回该函数的返回值

3. 面向对象的封装

-- 类Class的声明,其实就是个table,这里有两个成员变量x,y
Class =
{x = 1,y = 2
}-- 设置metatable的元方法__index,指向表Class自己
Class.__index = Class-- 构造函数,叫什么名字无所谓,这里采用了C++的new名字
function Class:new(x, y)print("Class:模拟构造函数new()")-- 新建一个对象,这样通过Class:new()函数创建的每一个实例都是独立的local tempObj = {}tempObj.x = xtempObj.y = y-- 设置新对象的metatable,谨记:这一步非常重要setmetatable(tempObj,Class)-- 返回这个新创建的对象return tempObj
end-- 类的其他成员函数1
function Class:Print()print("Class:Print()")print("x = "..self.x..", y = "..self.y)
end-- 类的其他成员函数2
function Class:Add(val)print("Class:Add()")self.x = self.x + valself.y = self.y + val
end-- 类的其他成员函数3
function Class:Modify()print("Class:Modify()")self.x = 11self.y = 22
end-- 下面是测试代码-- 新构造一个类实例
local Obj = Class:new(11,22)-- 调用函数Print()进行打印
Obj:Print()-- 调用函数Add()进行加操作
Obj:Add(5)-- 再次调用函数Print()进行打印,会发现调用Add()函数确实成功了
Obj:Print()-- 做修改
Obj:Modify()-- 再次调用函数Print()进行打印,会发现调用Modify()函数确实成功了
Obj:Print()-- 这里打印出Class本身的数据,会发现数据没有改动,说明是新建的类实例互不影响
print("Class Class.x = "..Class.x..", Class.y = "..Class.y)

测试结果如下:

4. 面向对象的继承多态

--------------------------------------   基类Class    -------------------------------------------- 类Class的声明,其实就是个table,这里有两个成员变量x,y
Class =
{x = 0,y = 0
}-- 设置metatable的元方法__index,指向表Class自己
Class.__index = Class-- 构造函数,叫什么名字无所谓,这里采用了C++的new名字
function Class:new(x, y)print("Class:模拟构造函数")-- 新建一个对象,这样通过Class:new()函数创建的每一个实例都是独立的local tempObj = {}tempObj.x = xtempObj.y = y-- 设置新对象的metatable,谨记:这一步非常重要setmetatable(tempObj,Class)-- 返回这个新创建的对象return tempObj
end-- 类的其他成员函数1
function Class:Print()print("Class:Print() x = "..self.x..", y = "..self.y)
end-- 类的其他成员函数2
function Class:Add(val)print("Class:Add()")self.x = self.x + valself.y = self.y + val
end-- 类的其他成员函数3
function Class:Modify()print("Class:Modify()")self.x = 111self.y = 222
end--------------------------------------   子类SubClass    ----------------------------------------- 子类SubClass的声明,这里又声明了一个新的变量z
SubClass =
{z = 0
}-- 设置元表为Class
setmetatable(SubClass, Class)-- 设置metatable的元方法__index,指向表SubClass自己
SubClass.__index = SubClass-- 构造函数
function SubClass:new(x,y,z)print("模拟构造函数:SubClass")-- 先调用父类的构造函数,构造出一个父类的实例local tempObj = Class:new(x,y)-- 将该对象的元表指向SubClass,谨记:这步非常重要,一定不要弄错了,是SubClasssetmetatable(tempObj,SubClass)-- 新属性z赋值,有了子类自己的数据,这样就是子类实例了tempObj.z = zreturn tempObj
end-- 定义一个新的成员函数
function SubClass:SubPrint()print("SubClass:SubPrint() x = "..self.x..", y = "..self.y..", z = "..self.z)
end-- 重定义父类的函数Add(),注意:和父类的不同,这里是增加了2倍的val
function SubClass:Add(val)print("SubClass:Add()")self.x = self.x + 2*valself.y = self.y + 2*val
end-------------------------------------    下面是测试代码      ------------------------------------- 构造一个基类实例
local Obj = Class:new(11,22)-- 调用函数Print()进行打印
Obj:Print()-- 调用函数Add()进行加操作
Obj:Add(5)-- 再次调用函数Print()进行打印,会发现调用Add()函数确实成功了
Obj:Print()-- 做修改
Obj:Modify()-- 再次调用函数Print()进行打印,会发现调用Modify()函数确实成功了
Obj:Print()-- 这里打印出Class本身的数据,会发现数据没有改动,说明是新建的类实例互不影响
print("Class Class.x = "..Class.x..", Class.y = "..Class.y)print("\n")-- 构造一个子类实例
local SubObj = SubClass:new(1,2,3)-- 访问父类的函数
SubObj:Print()-- 访问子类自己的函数
SubObj:SubPrint()-- 调用Add(),这里会发现实际调用的是子类的Add()函数,即实现了多态
SubObj:Add(5)-- 再次调用自己的函数,会发现调用自己的Add()函数确实成功了
SubObj:SubPrint()

测试结果如下:

lua的面向对象编程,封装,继承,多态的实现相关推荐

  1. 面向对象编程 封装 继承 多态(三大特征)(第三篇)

    封装 封装是面向对象编程的三大特征之一. 封装有两方面的含义: 1.将数据(属性)和行为(方法)包装到类对象中.方法内部对属性进行操作,在类对象的外部调用方法.这样,无需关心方法内部的具体实现细节,从 ...

  2. c语言编程 菲薄拉,C语言设计模式-封装-继承-多态

    快过年了,手头的工作慢慢也就少了,所以,研究技术的时间就多了很多时间,前些天在CSDN一博客看到有大牛在讨论C的设计模式,正好看到了,我也有兴趣转发,修改,研究一下. 记得读大学的时候,老师就告诉我们 ...

  3. Day55-每日一道Java面试题-Java 面向对象编程三大特性: 封装 继承 多态

    Java 面向对象编程三大特性: 封装 继承 多态 封装 封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,我们大可不必提供方法给外界访问.但是如果一个类没有 ...

  4. 面向对象 编程及面向对象三大属性:封装 继承 多态

    面向对象 面向对象(Object Oriented,OO)是软件开发方法.面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统.交互式界面.应用结构.应用平台.分布式系统.网络管理结构. ...

  5. python面向对象编程 -- 封装、继承

    面向对象编程 -- 封装.继承 面向对象编程三要素:封装.继承和多态.本文主要看和封装.继承相关的概念:在python中多态的概念比较模糊,本文不做讨论. 1 封装 封装:将数据和操作组装到一起,对外 ...

  6. python多态的三种表现形式_python小结----面向对象的三大特征(封装,继承,多态)

    面向对象的三大特征: 封装,继承,多态 面向对象的编程思想核心:高类聚,低耦合–程序的设计模式范畴 封装 什么是封装: 在面向对象编程的思想中,对代码进行高度封装,封装又叫包装 封装就是指将数据或者函 ...

  7. python 参数类型的多态_【Python】面向对象:类与对象\封装\继承\多态

    六.Python面向对象--类与对象\封装\继承\多态 1.什么是面向对象编程 1.1 程序设计的范式:程序可控,易于理解 1.2 抽象并建立对象模型 1.3 程序是不同对象相互调用的逻辑.每个对象在 ...

  8. python面向对象编程(封装与继承)

    一. 面向过程编程语言 "面向过程"(Procedure Oriented)是一种以过程为中心的编程思想.分析出解决问题所需要的步 骤,然后用函数把这些步骤一步一步实现,使用的时候 ...

  9. 大数据笔记8—java基础篇4(面向对象-封装-继承-多态)

    面向对象 一.面向对象 1.面向过程 1.2.举例 1.3.总结 二.面向对象 1.简述 2.举例 3.思想特点 2.1.类的定义格式 2.1.1.简述 2.2.2.格式 2.3.3.示例 三.类的使 ...

  10. Java面向对象三大特性(封装继承多态)解释及案例

    文章目录 包 包基本语法 命名规则 命名规范 导入包实例 访问修饰符 面向对象编程-封装 面向对象编程-继承 super关键词 super和this的比较 方法重写/覆盖 (override) 注意事 ...

最新文章

  1. 编程模拟洗牌和发牌过程c语言,洗牌发牌模拟系统课程设计报告.doc
  2. 解析深度学习:卷积神经网络原理与视觉实践
  3. 修改VIM恶心的注释自动格式化
  4. centos7开启vnc服务_Centos7 VNC远程桌面服务安装配置
  5. boost::interprocess::wmanaged_external_buffer用法的测试程序
  6. LeetCode——Backtracking
  7. 樱桃小丸子-每集标题
  8. C++面试题:list和vector有什么区别?
  9. HDU2602Bone Collector(DP,0/1背包)
  10. 现代操作系统 第六章 死锁 习题答案
  11. Setup Factory 卸载 Invalid Start mode :archive filename
  12. 深度学习——时间序列模型评价指标总结
  13. C#打造一个开源webgis(四)地图客户端(上)
  14. Cocos2d-x制作《单机斗地主》源码解剖1:创建一副扑克牌
  15. [通信技术]Iub接口协议——专用传输信道(DCH)的用户平面协议
  16. 基于C++和OpenCV的中心线提取算法
  17. 天空的心事,只有云懂
  18. Failure to find xxx:jar:0.0.1 in https://repo.maven.apache.org/maven2 was cached in the local re
  19. 前端工程师必备的 10款开发工具
  20. 二、谷歌阻止苹果,谁来阻止谷歌

热门文章

  1. 计篇-之一文言文翻译
  2. 主动防御型杀毒软件的技术探讨
  3. CodeForces - 548D Mike and Feet(单调栈)
  4. POJ - 1459 Power Network(网络流-最大流)
  5. POJ - 1273 Drainage Ditches(最大流)
  6. qduoj - WHY吃糖果(二分套二分)
  7. 华为杯数学建模优秀论文_数学建模经典例题(2011年国赛A题与优秀论文)
  8. bootstrap 图片预览_教你简单用Photoshop制作GIF图片
  9. js:点击button后返回值
  10. mysql流量控制_Daloradius限制上网流量