面向对象

>> 把一组数据结构和处理它们的方法组成对象(object),把相同行为的对象归纳为类(class)
>> 通过类的封装(encapsulation)隐藏内部细节
>> 通过继承(inheritance)实现类的特化(specialization)/泛化(generalization)
>> 通过多态(polymorphism)实现基于对象类型的动态分派(dynamic dispatch)

1.lua中的类

lua中其实是没有类的,有的只是表(table),而类之间的继承也就是将父类的表连到了一起,派生类中没有找到的属性和方法就通过元表查找父类

2.lua中类的属性

classA = {width =10, height=10}

classA={}

classA.width=10

classA.height=10

两种方法都可以,通过点self.width统一调用

3.类方法

[cpp] view plaincopy

function Box:collsion()
– 默认第一个参数隐藏传递self,可以通过self.xxx 调用属性和方法
end

function Box.create(self)
–必须手动传递参数self,否则无法用self.xxx调用属性和方法
end

4.类与元表的用法

  • lua查找一个表元素时的规则,其实就是如下3个步骤:
    • 4.1.在表中查找,如果找到,返回该元素,找不到则继续
    • 4.2.判断该表是否有元表,如果没有元表,返回nil,有元表则继续
    • 4.3.判断元表有没有index方法,如果index方法为nil,则返回nil;如果index方法是一个表,则重复1、2、3;如果index方法是一个函数,则返回该函数的返回值

在Lua中,函数的声明和调用可以用”:”和”.”,属性调用全部用点”.”

我们知道,对象由属性和方法组成。LUA中最基本的结构是table,所以需要用table来描述对象的属性。

lua中的function可以用来表示方法。那么LUA中的类可以通过table + function模拟出来。

至于继承,可以通过metetable模拟出来(不推荐用,只模拟最基本的对象大部分时间够用了)。

Lua中的表不仅在某种意义上是一种对象。像对象一样,表也有状态(成员变量);也有与对象的值独立的本性,特别是拥有两个不同值的对象(table)代表两个不同的对象;一个对象在不同的时候也可以有不同的值,但他始终是一个对象;与对象类似,表的生命周期与其由什么创建、在哪创建没有关系。

1. 初步面向对象
ObjectData = {balance = 0}

function ObjectData.count( v )
– body
print("value is :", v)
end

a = ObjectData
a.count("iCocos")
– value is : iCocos

2. 面向对象模拟
ObjectData = {balance = 100}

function ObjectData.count( self, v )
self.balance = self.balance + v
print("value is :", v, self.balance)
end

a = ObjectData
a.count(a, 99) – 传递self
– value is : 99 199

a:count(99) – 不传self,直接把a作为self传递进入,
– value is : 99 298

Lua中的继承

先来定义一个基类,

使用前面讲的setmetatable来实现基本的元表

local _M = {}

function _M:new(name)
return setmetatable({ name = name}, { __index = _M })
end

function _M:show()
print(self.name .. ": show in parent:")
end

function _M:hello(arg)
print(self.name .. ": hello in parent:" .. tostring(arg))
end

return  _M
子类的实现
local parent = require("parent")

local _M = {}

function _M:new()
local obj = parent:new("the child")
local super_mt = getmetatable(obj)
– 当方法在子类中查询不到时,再去父类中去查找。
setmetatable(_M, super_mt)
– 这样设置后,可以通过self.super.method(self, …) 调用父类的已被覆盖的方法。
obj.super = setmetatable({}, super_mt)
return setmetatable(obj, { __index = _M })
end

– 覆盖父类的方法。
function _M:hello()
– 只能使用这种方法调用基类的方法。
self.super.hello(self, "call from child")
print(tostring(self.name) … ": hello in child")
end

return _M

test.lua (使用)

– local parent = require("parent")
local child = require("child")

local c = child:new()
– 从parent继承的show方法
c:show()
– child自己的方法。
c:hello()

执行lua test.lua 后 输出:

the child: show in parent:
the child: hello in parent:call from child
the child: hello in child
  • 可以看到:
    • show是继承了父类的方法。
    • hello是由子类覆盖了,并且在hello中调用了父类的hello方法。