原始代码:
local _class={}
function class(super)
local class_type={}
class_type.ctor=false
class_type.super=super
class_type.new=function(...)
local obj={}
do
local create
create = function(c,...)
if c.super then
create(c.super,...)
end
if c.ctor then
c.ctor(obj,...)
end
end
create(class_type,...)
end
setmetatable(obj,{ __index=_class[class_type] })
return obj
end
local vtbl={}
_class[class_type]=vtbl
setmetatable(class_type,{__newindex=
function(t,k,v)
vtbl[k]=v
end
})
if super then
setmetatable(vtbl,{__index=
function(t,k)
local ret=_class[super][k]
vtbl[k]=ret
return ret
end
})
end
return class_type
end
不足
这个设计有个不足之处是派生类函数中没法调用基类的同名函数。下面想办法改进下。
改进一(仅限于两层继承使用)
这段代码增加了一句:
obj.super = _class[superClass]
为的是在派生类中通过
self.super.xxx(self, ...)
的方式调用基类函数。但是仅限于两层继承,当多层继承时,例如 CBase ClassA ClassB ,在ClassB中调用self.super.inc是会调到ClassA中去,但是如果ClassA中继续调用self.super.inc, 就会不断在ClassA的当前函数中不断循环,因为self.super引用的是同一个表。因此不太建议使用这个方法。
例如如下代码片段就会有问题:
local _class={}
function class(superClass)
local class_type={}
class_type.ctor=false
class_type.super=superClass
class_type.new=function(...)
local obj={}
setmetatable(obj,{ __index=_class[class_type] })
obj.super = _class[superClass] --这里只适应于两层集成,多层集成,会有死循环。因为对象是同一个,会不断重复调用
do
local create
create = function(Class, ...)
local o = nil
if Class.super then
create(Class.super, ...)
end
if Class.ctor then
Class.ctor(obj, ...)
end
end
create(class_type, ...)
end
return obj
end
local vtbl={}
_class[class_type]=vtbl
setmetatable(class_type, {__newindex=
function(t, funcName, funcAddr)
vtbl[funcName] = funcAddr
end
})
if superClass then
setmetatable(vtbl,{__index=
function(t,funcName)
local funcAddr=_class[superClass][funcName]
vtbl[funcName]=funcAddr
return funcAddr
end
})
end
return class_type
end
-------------------------------------------------------
CBase = class()
function CBase:ctor(name)
self.name = name
self.x = 0
self.y = 0
print("CBase:ctor() x = "..tostring(self.x))
print("CBase:ctor() y = "..tostring(self.y))
end
function CBase:show()
print('CBase:show()')
print("x = "..tostring(self.x))
print("y = "..tostring(self.y))
end
function CBase:inc()
print('CBase:inc()')
self.x = self.x + 1
self.y = self.y + 1
print("x = "..tostring(self.x))
print("y = "..tostring(self.y))
end
-------------------------------------------------------
ClassA = class(CBase)
function ClassA:ctor(name)
self.name = name
self.y = 2
print("ClassA:ctor() y = "..tostring(self.y))
end
function ClassA:inc(n)
n = n or 1
self.super.inc(self, n) --注意这里
print("ClassA::inc()")
self.y = self.y + n
print('x = '..tostring(self.x))
print('y = '..tostring(self.y))
end
-------------------------------------------------------
ClassB = class(ClassA)
function ClassB:inc(n)
self.super.inc(self, n) --
print("ClassB::inc()")
end
a = ClassA.new('ClassA')
a:show()
a:inc()
print('--------')
b = ClassB.new('ClassB')
b:inc(4) --这里调进去后会在ClassA:inc中死循环
print(b.name)
b:show()
改进二
只要在原始代码后面增加一小段代码:
local __super = _class
function super(class_type)
return __super[class_type]
end
其实只要加一句:
function super(class_type)
return _class[class_type]
end
使用__super代替_class只要是方便理解。
使用时便可以这样调用:
super(ClassA).inc(self, ...)
当然也可以使用以下任何一种:
__super[CBase].inc(self, ...)
_class[CBase]['inc'](self, ...)
_class[CBase].inc(self, ...)
__super[CBase]['inc'](self, ...)
__super[CBase].inc(self, ...)
修改后的
--基类
local _class={}
function class(superClass)
local class_type={}
class_type.ctor=false
class_type.super=superClass
class_type.new=function(...)
local obj={}
setmetatable(obj,{ __index=_class[class_type] })
--obj.super = _class[superClass],这里只适应于两层集成,多层集成,会有死循环。因为对象是同一个,会不断重复调用
do
local create
create = function(Class, ...)
local o = nil
if Class.super then
create(Class.super, ...)
end
if Class.ctor then
Class.ctor(obj, ...)
end
end
create(class_type, ...)
end
return obj
end
local vtbl={}
_class[class_type]=vtbl
setmetatable(class_type, {__newindex=
function(t, funcName, funcAddr)
vtbl[funcName] = funcAddr
end
})
if superClass then
setmetatable(vtbl,{__index=
function(t,funcName)
local funcAddr=_class[superClass][funcName]
vtbl[funcName]=funcAddr
return funcAddr
end
})
end
return class_type
end
local __super = _class
function super(class_type)
return __super[class_type]
end
示例代码
CBase = class() -- 定义一个基类 CBase
function CBase:ctor(name) -- 定义 CBase 的构造函数
self.name = name
self.x = 0
self.y = 0
print("CBase:ctor() x = "..tostring(self.x))
print("CBase:ctor() y = "..tostring(self.y))
end
function CBase:show() -- 定义一个成员函数 CBase:show
print('CBase:show()')
print("x = "..tostring(self.x))
print("y = "..tostring(self.y))
end
function CBase:inc() -- 定义另一个成员函数 CBase:inc
print('CBase:inc()')
self.x = self.x + 1
self.y = self.y + 1
print("x = "..tostring(self.x))
print("y = "..tostring(self.y))
end
-------------------------------------------------------
ClassA = class(CBase) -- 定义一个类 ClassA 继承于 CBase
function ClassA:ctor(name) -- 定义 ClassA 的构造函数
self.name = name
self.y = 2
print("ClassA:ctor() y = "..tostring(self.y))
end
function ClassA:inc(n) -- 重载 CBase:inc 为 ClassA:inc
n = n or 1
__super[CBase].inc(self, n)
--_class[CBase]['inc'](self, n)
--_class[CBase].inc(self, n)
print("ClassA::inc()")
--print(_class[CBase]:inc(self))
self.y = self.y + n
print('x = '..tostring(self.x))
print('y = '..tostring(self.y))
end
-------------------------------------------------------
ClassB = class(ClassA)
function ClassB:inc(n)
--__super[ClassA].inc(self, n) --u can try:__super[CBase].inc(self, n)
super(ClassA).inc(self, n)
--_class[ClassA]['inc'](self, n)
--_class[ClassA].inc(self, n)
print("ClassB::inc()")
end
a = ClassA.new('ClassA')
a:show()
a:inc()
print('--------')
b = ClassB.new('ClassB')
b:inc(4)
print(b.name)
b:show()
-----------------
BaseController = class()
function BaseController:ctor()
self.mLayer = nil
--self.mLayer = cc.Layer:create()
self.mLayer = 'haha'
end
function BaseController:create()
end
function BaseController:remove()
if self.mLayer then
--self.mLayer:removeFromParent(true)
self.mLayer = nil
end
end
function BaseController:getLayer()
return self.mLayer
end
Test = class(BaseController)
function Test:create()
print('-----------')
super(BaseController).create(self)
print(self.mLayer)
print(self:getLayer(Test))
end
test = Test.new()
test.fun = function()
print('fun')
end
test:create()
print(test:getLayer())
test.fun()
使用技巧
实际使用方法:
- 1、派生类的构造函数(ctor)可以声明也可以不声明。
- 2、类的函数声明的时候用冒号。
- 3、如果想用表,可以这样结合使用: ```lua Test = class(BaseController) –声明一个派生类
function Test:create() –类函数,用冒号声明,里面可以使用self print(‘———–’) self.x = 1 end
test = Test.new() –此时test是一个表
test.fun = function() –此时fun是test表的一个字段,使用时就要和类函数区别开来,就要用点的形式,这个函数里不能使用self print(‘fun’) –可以看做是静态函数。 end
test:create() –这个调用的是类函数,一定要用冒号 print(test:getLayer()) test.fun() –调用表的一个字段函数,用点
return test –在一个Lua文件中返回test的好处是既可以当做类对象使用(调用函数用冒号),又可以使用表里面的函数(调用函数用点)。 ```
参考
文档信息
- 本文作者:zhupite
- 本文链接:https://zhupite.com/lua/lua-class.html
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)