版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yzf279533105/article/details/80099358
————————————————
版权声明:本文为CSDN博主「YZF_Kevin」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yzf279533105/article/details/80099358
参考YZF_Kevin博文的笔记
lua中的语法糖
lua中的函数默认都是有self传递进去的,self相当于C++类中函数的this指针,语法糖会自动给我们传递self
local a = {x = 99}
-- 打印函数,这里要访问表a中的变量x,必须指明self.x或者a.x,不然会报错
function a:Print()
print(self.x)
end
-- 想调用a的Print()函数,可以这样写,注意参数是a,否则调用出错
a.Print(a)
-- 也可以这样写,即用:代替. 且可不用传入参数a
a:Print()
Lua面向对象的原理(基于元表metatable和元方法__index)
如果访问了lua表中不存在的元素时,就会触发lua的一套查找机制,也是凭借这个机制,才能实现面向对象
元表像是一个备用查找表,假设表A的元表是B,那么在A中找不到的东西就会尝试在B中去找,设置元表的函数如下
setmetatable(A,B),这样表B就被设置为A的元表,当A中找不到某个变量时就会到B中进行查找
A = {}
B = {a=99}
-- 设置表B为表A的元表
setmetatable(A,B)
-- 再访问表A中不存在的变量a
print(A.a) --> nil
打印结果依然是nil
因为表B的元方法__index没有赋值。按照理解,元方法__index是用来确定一个 表在被作为元表时的查找方法
修改后,代码如下
A={}
B={a=99}
-- 给表B的元方法__index进行赋值
B.__index = B
-- 设置表B为表A的元素
setmetatable(A,B)
-- 再访问表A中不存在的变量a
print(A.a) -->99
打印结果是: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 = {}
B = {}
B.__index = function(table, key)
print("在元表中访问了变量"..key)
return 88
end
setmetatable(A,B)
print(A.a) -->88
打印结果:
在元表中访问了变量a
88
总结元表的查找步骤:
1.在表中查找,如果找到,返回该元素,找不到则继续步骤2
2.判断该表是否有元表,如果没有元表,返回nil,有元表则继续步骤3
3.判断元表有没有__index方法,如果__index方法为nil,则返回nil;如果__index方法是一个表,则重复步骤1、2、3;如果__index方法是一个函数,则调用该函数,并返回该函数的返回值
面向对象的封装
-- 类Class的声明,其实就是个table,这里有两个成员变量x,y
Class = {x=1,y=2}
-- 设置metatable的元方法__index,指向表Class自己
Class.__index = Class
-- 构造函数,这里用new名字
function Class:new(x,y)
print("Class:模拟构造函数new()")
-- 新建一个对象,这样通过Class:new()函数创建的每一个实例都是独立的
local tempObj = {}
tempObj.x = x
tempObj.y = y
-- 设置新对象的metatable,谨记:这一步非常重要
setmetatable(tempObj, Class)
-- 返回这个新创建的对象
return tempObj
end
function Class:Print()
print("Class:Print()")
print("x = "..self.x..", y = "..self.y)
end
function Class:Add(val)
print("Class:Add()")
self.x = self.x + val
self.y = self.y + val
end
function Class:Modify()
print("Class:Modify()")
self.x = 11
self.y = 22
end
local Obj = Class:new(11,22)
Obj:Print()
Obj:Add(5)
Obj:Print()
Obj:Modify()
-- 这里打印出Class本身的数据,会发现数据没有改动,说明是新建的类实例互不影响
print("Class Class.x="..Class.x..",Class.y"..Class.y)
测试结果:
Class:模拟构造函数new()
Class:Print()
x = 11 , y = 22
Class:Add()
Class:Print()
x = 16 , y = 27
Class:Modify()
Class:Print()
x = 11 , y = 22
Class Class.x = 1 , Class.y = 2
面向对象的继承和多态
-- 类Class的声明,其实就是个table,这里有两个成员变量x,y
Class = {x=0,y=0}
-- 设置metatable的元方法__index,指向表Class自己
Class.__index = Class
-- 构造函数,这里用new名字
function Class:new(x,y)
print("Class:模拟构造函数")
-- 新建一个对象,这样通过Class:new()函数创建的每一个实例都是独立的
local tempObj = {}
tempObj.x = x
tempObj.y = y
-- 设置新对象的metatable,谨记:这一步非常重要
setmetatable(tempObj, Class)
-- 返回这个新创建的对象
return tempObj
end
function Class:Print()
print("Class:Print()")
print("x = "..self.x..", y = "..self.y)
end
function Class:Add(val)
print("Class:Add()")
self.x = self.x + val
self.y = self.y + val
end
function Class:Modify()
print("Class:Modify()")
self.x = 11
self.y = 22
end
-- 子类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,谨记:这步非常重要,是SubClass
setmetatable(tempObj, SubClass)
-- 新属性z赋值,有了子类自己的数据,这样就是子类实例了
tempObj.z = z
return tempObj
end
-- 定义一个新的成员函数
function SubClass:SubPrint()
print("SubClass:SubPrint() x = "..self.x..", y = "..self.y..", z = "..self.z)
end
-- 重定义父类的函数Add()
function SubClass:Add(val)
print("SubClass:Add()")
self.x = self.x + 2*val
self.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()
输出结果:
模拟构造函数
Print() x = 11, y = 22
Add()
Print() x = 16, y = 27
Modify()
Print() x = 11, y = 22
Class.x = 0, Class.y = 0
模拟构造函数:SubClass
Class:模拟构造函数
Class:Print() x = 1, y = 2
SubClass:SubPrint() x = 1, y = 2, z = 3
SubClass:Add()
SubClass:SubPrint() x = 11, y = 12, z = 3