lua重新学习笔记4(lua的面向对象实现)

版权声明:本文为博主原创文章,遵循 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

 

你可能感兴趣的:(lua笔记)