Lua本身是没有class之类的关键字的,但是我们可以巧妙利用function也是值和table的特性来实现面向对象的特性。

通过复制表的实现

Lua中的类也是一个table对象,下面我们看看一个简单的类的定义:

 People = {}--定义表 People

 --添加方法的第一种方式
People.talk = function()
print("people talk.")
end --添加方法的第二种方式
function People.say()
print("people say.")
end People.talk()--people talk.
People.say()--people say.

我们发现添加一个方法有两种方式,这两种方式的效果都是一致的,至于使用哪种就看个人喜好了。

通过拷贝创建实例

不知道大家发现没有,上面的示例中并没有创建实例这个步骤,而在面向对象中,类是需要创建实例来使用的,下面我们就用复制的方法来创建实例:

 --克隆一个表
function clone(obj)
local instance = {} for key, var in pairs(obj) do
instance[key] = var
end return instance;
end People = {}--定义表 People --定义方法
People.talk = function()
print("people talk.")
end --创建 People 的实例
local p = clone(People)
p.talk()--people talk.

构造函数

我们发现虽然可以创建实例了,但是却没有构造函数,下面我们把构造函数也添加进去:

 --克隆一个表
function clone(obj)
local instance = {} for key, var in pairs(obj) do
instance[key] = var
end return instance;
end People = {}--定义表 People --定义构造函数
People.new = function(name)
local ins = clone(People)
ins.name = name;
return ins
end --定义方法
People.talk = function(self)
print(self.name.." talk.")
end --创建 People 的实例
local p = People.new("Li Lei")
p.talk(p)--people talk.
p:talk()--使用 : 号可以省略 self 的填写, 效果和上一行一致

这里引入了一个新的变量self和“:”符号,下面我们来说说:

self

self作为第一个参数表示调用则本身。

.号和:号

调用时为了传递调用者本身,所以第一个参数需要将自身传入,这是.号的写法;

如果使用:号,则默认第一个参数传入调用者本身,无需我们再写第一个参数了,我们可以从第二个参数开始写,但是函数声明时仍然要写第一个参数self的。

定义函数时也可以使用:号进行定义,这样定义方法时也可以省略self参数,但是写法只能写成function tab:foo() end这样的形式,如下:

 obj = {name = "Li Lei"}
--.号的写法和调用
obj.foo1 = function()
print "foo1"
end
function obj.foo2(self)
print(self.name.."foo2")
end
obj.foo1()--foo1
obj.foo2(obj)--Li Leifoo2
--:号的写法和定义
--[[注释掉的这种写法是不允许的
obj:foo3 = function()
print(self.name.."foo3")
end
]]
function obj:foo4()
print(self.name.."foo4")
end
obj:foo4()--Li Leifoo4

继承

下面我们来看看如何实现类的继承:

 --克隆一个表
function clone(obj)
local instance = {} for key, var in pairs(obj) do
instance[key] = var
end return instance;
end People = {}--定义表 People --定义构造函数
People.new = function(name)
local ins = clone(People)
ins.name = name;
return ins
end --定义方法
People.talk = function(self)
print(self.name.." talk.")
end --定义方法2
People.talk2 = function(self)
print(self.name.." talk2.")
end --创建 People 的实例
local p = People.new("Li Lei")
p.talk(p)--people talk.
p:talk()--使用 : 号可以省略 self 的填写, 效果和上一行一致 --下面是关于继承的实现 --将 origin 表的值复制到 dist 表中
function copy(origin, dist)
for key, var in pairs(origin) do
dist[key] = var
end
end Man = {}--定义表 Man, 继承自 People Man.new = function(name)
local ins = People.new(name)--创建继承的类, 这样就拥有了继承类的所有属性
copy(Man, ins)--将 Man 的属性附加到实例
return ins
end --定义方法
Man.say = function()
print("Man say!")
end --重写方法
Man.talk2 = function(self)
print(self.name.." talk2. (Man)")
end --创建 Man 的实例
local m = Man.new("Han Meimei")
m:talk()--Han Meimei talk.
m:talk2()--Han Meimei talk2. (Man)
m:say()--Man say!

简单来说,就是先创建父类的实例,然后把新类的所有属性都拷贝到刚创建的实例上即可。

通过函数闭包的实现

我们可以通过在函数内定义函数的方式来实现面向对象的特性:

 --定义方法直接返回表的实例
function People(name)
local ins = {}--创建表 --初始化函数
local function init()
ins.name = name
end --定义方法
ins.talk = function()
print(ins.name.." talk.")
end --定义带参数的方法
ins.talk2 = function(content)
print(ins.name.." talk "..content..".")
end -- self 可以省去了, 因为可以通过闭包的特性获取到, 或者如果要统一 : 符号可以这么写
ins.talk3 = function(self, content)
print(self.name.." talk "..content..".")
end init()--调用初始化函数 return ins
end --创建对象
p = People("Li Lei")
p:talk()--没有参数可以这么写
p.talk() --p:talk2("hello")--没有 self 参数不能这么调用了
p.talk2("hello") p:talk3("hello 2")
p.talk3(p, "hello 2")

这种写法的运行效率略低于上一种方法,但是却更加清晰,在实际使用时推荐使用该方法来编写类。

继承

使用这种写法也可以实现类的继承,如下:

 --定义方法直接返回表的实例
function People(name)
local ins = {}--创建表 --初始化函数
local function init()
ins.name = name
end --定义方法
ins.talk = function()
print(ins.name.." talk.")
end --定义带参数的方法
ins.talk2 = function(content)
print(ins.name.." talk "..content..".")
end -- self 可以省去了, 因为可以通过闭包的特性获取到, 或者如果要统一 : 符号可以这么写
ins.talk3 = function(self, content)
print(self.name.." talk "..content..".")
end init()--调用初始化函数 return ins
end --下面是继承的代码 function Man(name)
local ins = People(name)--关键: 创建一个 People 类的实例 --添加新项目
ins.say = function()
print(ins.name.." say.")
end --覆写老方法
ins.talk = function()
print(ins.name.." talk. (Man)")
end return ins
end m = Man("Han Meimei")
m.say()--Han Meimei say.
m.talk()--Han Meimei talk. (Man)

其实就是创建父类的对象后添加新的属性,比较容易理解。

Lua学习笔记(五):面向对象的实现的更多相关文章

  1. Lua学习笔记:面向对象

    Lua学习笔记:面向对象 https://blog.csdn.net/liutianshx2012/article/details/41921077 Lua 中只存在表(Table)这么唯一一种数据结 ...

  2. [转]LUA 学习笔记

    Lua 学习笔记 入门级 一.环境配置 方式一: 1.资源下载http://www.lua.org/download.html 2.用src中的源码创建了一个工程,注释调luac.c中main函数,生 ...

  3. Java学习笔记之---面向对象

    Java学习笔记之---面向对象 (一)封装 (1)封装的优点 良好的封装能够减少耦合. 类内部的结构可以自由修改. 可以对成员变量进行更精确的控制. 隐藏信息,实现细节. (2)实现封装的步骤 1. ...

  4. openresty 学习笔记五:访问RabbitMQ消息队列

    openresty 学习笔记五:访问RabbitMQ消息队列 之前通过比较选择,决定采用RabbitMQ这种消息队列来做中间件,目的舒缓是为了让整个架构的瓶颈环节.这里是做具体实施,用lua访问Rab ...

  5. C#可扩展编程之MEF学习笔记(五):MEF高级进阶

    好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四篇,MEF中比较常用 ...

  6. (转)Qt Model/View 学习笔记 (五)——View 类

    Qt Model/View 学习笔记 (五) View 类 概念 在model/view架构中,view从model中获得数据项然后显示给用户.数据显示的方式不必与model提供的表示方式相同,可以与 ...

  7. Lua 学习笔记(一)

    Lua学习笔记 1.lua的优势 a.可扩张性     b.简单     c.高效率     d.和平台无关 2.注释 a.单行注释 --        b.多行注释 --[[  --]] 3.类型和 ...

  8. Lua学习笔记6:C++和Lua的相互调用

        曾经一直用C++写代码.话说近期刚换工作.项目组中的是cocos2dx-lua,各种被虐的非常慘啊有木有.     新建cocos2dx-lua项目.打开class能够发现,事实上就是C++项 ...

  9. java之jvm学习笔记五(实践写自己的类装载器)

    java之jvm学习笔记五(实践写自己的类装载器) 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和第四节我们一直在强调一句话,类 ...

  10. UML和模式应用学习笔记-1(面向对象分析和设计)

    UML和模式应用学习笔记-1(面向对象分析和设计) 而只是对情节的记录:此处的用例场景为:游戏者请求掷骰子.系统展示结果:如果骰子的总点数是7,则游戏者赢得游戏,否则为输 (2)定义领域模型:在领域模 ...

随机推荐

  1. Qt之QTableView添加复选框(QAbstractItemDelegate)

    简述 上节分享了使用自定义模型QAbstractTableModel来实现复选框.下面我们来介绍另外一种方式: 自定义委托-QAbstractItemDelegate. 简述 效果 QAbstract ...

  2. 本来运行的好的Ajax.dll怎么突然不起作用了

    客户中有个好多年前老项目用了Ajax.dll,前几天突然不起作用了. 问了下原因,系统从Windows Server2003 升级为 Windows Server 2008了,IIS也从6升级成7了. ...

  3. Android-Universal-Image-Loader

    基本以后都不用了,所以自己就不总结了 http://www.cnblogs.com/kissazi2/p/3886563.html http://www.cnblogs.com/kissazi2/p/ ...

  4. 如何让你的 Asp.Net Web Api 接口,拥抱支持跨域访问。

    由于 web api 项目通常是被做成了一个独立站点,来提供数据,在做web api 项目的时候,不免前端会遇到跨域访问接口的问题. 刚开始没做任何处理,用jsonp的方式调用 web api 接口, ...

  5. HDU 5818 Joint Stacks

    Joint Stacks Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tota ...

  6. HDU 5783 Divide the Sequence

    Divide the Sequence Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Othe ...

  7. C# 多线程传参 三种实例

    //using Thread to download files //1111111111111111 foreach (var str in listDownloadPdf) { //string ...

  8. 2016传统行业“互联网+”元年,你准备好了吗?

    李克强总理在2015年的政府报告中的提出了"互联网+"的概念! 2015年,几十.上百本以"互联网+"作为书名的书出版! 2015年,各种传统行业的信息化被冠上 ...

  9. Java Spring boot 系列目录

    Spring boot 介绍 Spring boot 介绍 Spring boot 介绍 Spring boot 介绍 Spring boot 介绍 Spring boot 介绍 Spring boo ...

  10. ASP.NET MVC之Html.RenderAction

    WEB窗体模式开发惯了,切入MVC模式,好多东西都不懂,每一步都要查资料. 初步得来的一些知识点体会是: _Layout.cshtml就相当于母版页 然后partical视图(部分视图)就是用户控件. ...