问题
简述Lua实现面向对象的原理
思路
语法基础
__index和self
__index:子表找不到某个属性,就会找元表的__index对应的属性
self,类似 this,代表:的调用者,.点号的第一个默认参数
实现思路
一个表就是一个对象
封装: 我们可以认为 定义一个原型对象(类对象),原型对象派生出具体对象。
通过原型对象把self.__index=self,使得具体对象找不到对应方法时候,找元表 __index中的方法(就是原型对象里面找)
另外具体对象通过self来在成员函数中调用自己的成员字段
继承:可以上面同样的手法,从父类的 类对象派生出 子类的 类对象
子类 写的同名函数 ,子类调用的时候,由于自己找的到,所以不会找父类的同名函数
导致子类隐藏父类的同名函数
多重继承:1保存函数传递过来的父类对象,形成一个父类列表
2设置子类的元表的__index 为一个查找函数,这个函数会遍历父类列表 查找有没有对应的 字段
私有性:利用局部变量和闭包,一个表保存保存私有变量,一个表保存public的字段和接口函数
内部public 函数通过闭包 访问私有成员变量,把public 的那个表返回出去
代码
--[[原理
语法基础是 __index和self
__index:子表找不到某个属性,就会找元表的__index对应的属性
self:类似 this,代表:的调用者,.点号的第一个默认参数
local 局部的
封装:怎么共享方法,但是不共享变量, 我们可以认为 定义一个原型对象,具体的对象从原型对象里面出来
继承: 实际上,上方的封装的想法,换个角度就是继承的实现,怎么看,就是把 原型对象和对象
换成 父类和子类
私有性:利用局部变量,构造表的时候,只返回公开的成员表
怎么区分,本质上都是(表)对象,不过在具体写法规则上可以,类对象,写大写同时可以写方法和默认值
小写就当他是具体的对象
]]
--###类
-- 所有的对象都是 从原型对象派生出来,共享原型对象的方法
Account={balance=0;}
function Account:new (o)
o=o or{}
self.__index=self
setmetatable(o,self)
return o
end
function Account:deposit(v)
self.balance=self.balance+v;
end
function Account:withdraw(v)
if v>self.balance then
error"insufficient funds"
end
self.balance=self.balance-v
end
--###继承
--[[
继承: 实际上,上方的封装的想法,换个角度就是继承的实现,怎么看,就是把 原型对象和对象
换成 父类和子类
]]
--子类
SpecialAccount=Account:new()
--具体对象
s=SpecialAccount:new{limit=1000.00}
--子类盖住父类方法(注意不是重写)
function SpecialAccount:withdraw(v)
if v-self.balance>=self:getLimit() then
error"insufficient funds"
end
self.balance=self.balance-v
end
function SpecialAccount:getLimit()
return self.limit or 0
end
--###多重继承
--创建子类的时候,设置元表index 为查询父类 函数的函数
--在表 plist 列表查找‘k'
local function search(k,plist)
for i=1,#plist do
local v=plist[i][k] --尝试第i个超类
if v then return v end
end
end
function createClass(...)
local c={}--新类
local parents={...}--父类列表
--父类列表中查找缺少的办法, --t是调用者,这里顶替第一个默认参数(调用者)
--下面的例子,account 为t, getName为k
setmetatable(c,{__index =function (t,k)
return search(k,parents)
end})
-- 将c作为其实例的元表
c.__index=c;
--为新类定义一个新的构造函数
function c:new(o)
o=o or {}
setmetatable(o,c)
return o
end
return c --返回新类
end
Named={}
function Named:getName()
return self.name
end
function Named:setName(n)
self.name=n
end
NamedAccount =createClass(Account,Named)
account= NamedAccount:new{name="Paul"}
print(account:getName())
-- account:getName()== account.getName(account)==account["getName"](account)
--account 找原型 NamedAccount 然后找 元表index 调用方法
--找父类列表的方法
--####私有性
function newAccount(initalBalance)
--私有变量
local self={balance =initalBalance,
LIM=1000.00}
local withdraw=function (v)
self.balance=self.balance-v
end
local deposit=function (v)
self.balance=self.balance+v
end
local getBalance=function ()return self.balance end
--私有方法
local extra=function ()
if self.balance>self.LIM then
return self.balance*0.10
else
return 0;
end
end
local getBalanceExtra=function ()return self.balance +extra() end
return {
withdraw=withdraw,
deposit=deposit,
getBalance=getBalance,
getBalanceExtra=getBalanceExtra
}
end
acc1=newAccount(100.00)
acc1.withdraw(40.00)
print(acc1.getBalanceExtra())
acc2=newAccount(10000)
print(acc2.getBalanceExtra())
另外还有我经常用的唐老师的写法
Object={}
function Object:new()
local obj={}
--把自己设置为index,利用index特性:
--先找自己表有没有这个属性,没有找index(这里直接就是index),然后再没有找元表,元表的index,再找元表的元表,如果没有元表和这个属性返回nil
--self.__inde =self是使得自身表拥有Index特性
self.__index=self;
-- 调用者作为元表
setmetatable(obj,self);
--返回调用者的子表
return obj;
end
function Object:subClass(className)
--根据名字生成一张表 就是一个类
_G[className]={}
local obj=_G[className]
--设置自己的父类
obj.base=self
--子类设置元表
self.__index=self;
setmetatable(obj,self)
end
引用
小y老师的八股
【Unity面试篇】Unity 面试题总结甄选 |热更新与Lua语言 | ❤️持续更新❤️-腾讯云开发者社区-腾讯云 (tencent.com)
是函数覆盖还是函数隐藏,上面我比较严谨的考究了下
C++中函数重载、隐藏、覆盖和重写的区别-腾讯云开发者社区-腾讯云 (tencent.com)
上面的主要内容 来自
Lua程序设计(第4版) (豆瓣) (douban.com)
唐老师的Lua面向对象代码
后记
是什么促使我去发csdn了
1.某笔记软件好像限制文档数,感觉笔记要写好多,不够用了
2.前几天我看到q群里面大佬都在写博客,所以想尝试下
3.感觉以前写了好多重复的笔记,而且内容质量非常的低下,导致我复习的时候看自己的笔记都绷不住了,想通过csdn约束自己的笔记质量
4.以前有位前辈和我们说,要懂得量化自己的成果,我之前写了好多笔记,看了好的杂七杂八的,但最终好像没什么成果,还是希望通过这个记录自己的学习成果,避免重复写笔记,也告诉未来的自己,这段时间到底学了啥,干啥成果,不会后悔说,啊我怎么怎么懒,我有好好努力的(