详解QuickCocos2dX继承机制


这篇文章让我们来理解下QuickCocos2dx的继承机制,关于继承这个概念,是OO思想里提出来的。在C++中,我们就不说了; 在lua中,是用table配合元表metatable来实现面向对象的。下面分两部分来理解Quick中的继承机制。

##第一部分:LUA的继承

###充电站:元表

  • lua中的元表和js的原型非常相似,熟悉js的朋友应该发现了
  • 在lua中,每一个表都有TA的元表metatable,lua默认创建一个不带元表的新表:
1
2
t = {}
print(getmetatable(t)) --nil
  • 设置元表
1
2
3
4
mt = {name = "quick"}
t = {}
setmetatable(t, mt)
assert(getmetatalbe(t) == mt)

LuaInherit lua继承

图示代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
--====================Person======================
local Person = {}
Person.attack = 5

function Person:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end

function Person:setAttack(attack)
self.attack = attack
end

function Person:getAttack()
return self.attack
end


--====================Hero======================
local Hero = Person:new()
Hero.name = ""
Hero.skill = ""


--====================hero1,hero2======================
local hero1 = Hero:new()
hero1.name = "金刚狼"
hero1.skill = "甩开爪子切牛排"

local hero2 = Hero:new({name = "超人"})
hero2.skill = "内裤外穿走T台"


----====================================================
function printKeys(name, t)
print("======================" .. name)
for k, v in pairs(t) do
print(k)
end
end


printKeys("Person", Person)
printKeys("Person.__index", Person.__index)

printKeys("Hero", Hero)
printKeys("Hero.__index", Hero.__index)
printKeys("getmetatable(Hero).__index", getmetatable(Hero).__index)

printKeys("hero1", hero1)

printKeys("hero2", hero2)

结合log我们分析下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
======================Person
setAttack
__index
getAttack
new
attack
======================Person.__index
setAttack
__index
getAttack
new
attack
======================Hero
skill
name
__index
======================Hero.__index
skill
name
__index
======================getmetatable(Hero).__index
setAttack
__index
getAttack
new
attack
======================hero1
name
skill
======================hero2
name
skill
[Finished in 0.0s]

###转回正题

假如当我们调用hero1:setAttack(500)的时候,在hero1中是找不到setAttack方法的,这时候:

  1. lua会通过getmetatable(hero1)得到hero1的元表并到元表的__index域中去查找,箭头走向:3—》2
  2. 但仍然没找到,得到Hero元表并继续在其__index域中寻找,箭头走向:1—》0,这时候寻找到setAttack方法并且调用,由于setAttack方法,hero1会增加字段attack

##第二部分:QUICK的继承

quick的继承实现要考虑到对C++对象的继承和对lua对象的继承。对lua对象的继承我们第一部分已经用元表机制说明。当我们在quick中用class新建类时,始终要清醒的明白,我们新建的类其实就是返回一个lua表(cls).

继承的核心代码见framework/functions.luaclass(classname, super)函数。

为了方便理解,上个图先:

quick-x class

函数class(classname, super)有两个参数:

  • 参数1:classname,见名知意,类名
  • 参数2:super
    • 1.super的类型:superType = type(super)
    • 2.superType可以为function, table,当不为这两种类型的时候我们将之置为nil
    • 3.superType为function的时候,表示从C++对象继承,走图示2
    • 4.superType为table的时候,还要看其__ctype值,1表示继承自C++对象,走图1;2表示继承自lua表对象,走图3
    • 5.superType为nil的时候,从lua表继承,走图4

samples/coinFlip项目是个绝佳的例子,我们可以结合该范例进行理解。这里我就不赘述了。


更新:在谷歌邮件组Jacky的回复中,提到了另外一个朋友写的文章,非常不错,针对本文的第二部分讲解的很透彻,地址


你我是朋友,各拿一个苹果彼此交换,交换后仍然是各有一个苹果;倘若你有一个思想,我也有一种思想,而朋友间交流思想,那我们每个人就有两种思想了。 ——爱尔兰剧作家 萧伯纳

坚持原创技术分享,您的支持将鼓励我继续创作!