先说一下上一篇文章提到的class()函数,它接受二个参数,第一个是类名,第二个是基类,也就是只它只能从一个继承一个基类。我们之前提到过,继承其实是要实现代码的复用,显然只有单个基类的继承是无法有效实现代码复用的。例个例子
Bird =class("Bird") --鸟
function Bird:Fly() --鸟会飞
print("I can Fly")
end
Penguin =class("Penguin",Bird ) --企鹅,是一种鸟,所以它继承自鸟类,但是不会飞
function Penguin:Fly() --企鹅不会飞,所以要重写它的Fly函数
print("I can'n Fly")
end
Fish = class("Fish")
function Fish:Swim() --鱼会游
print("I can Swim")
end
Polarbear=class("Polarbear") --北极熊
function Polarbear:ILoveIce()--北极熊喜欢冰
print("I Love ice")
end
上述的例子,企鹅是鸟的一种继承自鸟类,但是,企鹅已经不会飞了,所以它得重写Fly函数,让它不能飞。但是企鹅可以游泳,要实现企鹅游泳,我们可以给它写一个游泳的函数
function Penguin:Swim() --给企鹅加上会游泳的函数
print("I can Swim")
end
同时,企鹅还喜欢冰,我们给它加上喜欢冰的函数
function Penguin:ILoveIce()--企鹅喜欢冰
print("I Love ice")
end
这样,最终的代码应该是这样的
Bird =class("Bird") --鸟
function Bird:Fly() --鸟会飞
print("I can Fly")
end
Fish = class("Fish")
function Fish:Swim() --鱼会游
print("I can Swim")
end
Polarbear=class("Polarbear") --北极熊
function Polarbear:ILoveIce()--北极熊喜欢冰
print("I Love ice")
end
Penguin =class("Penguin",Bird ) --企鹅,是一种鸟,所以它继承自鸟类,但是不会飞
function Penguin:Fly() --企鹅不会飞,所以要重写它的Fly函数
print("I can'n Fly")
end
function Penguin:Swim() --给企鹅加上会游泳的函数
print("I can Swim")
end
function Penguin:ILoveIce()--企鹅喜欢冰
print("I Love ice")
end
额没有发觉,企鹅实现的Swim和ILoveIce函数,其实和鱼和北极熊的是一样的,我们已经给鱼写了一个了,为什么我们还要给企鹅要写一个一模一样的啊?我们是不是可以复用一下这个代码?现在只是几行代码,要是函数多了, 函数的代码多了,复制代码也很累的。比如,让企鹅继承自鸟类,然后再继承一下鱼类,熊类的接口,啊,企鹅就能像鱼一样游泳,像北极熊一样在冰上玩啦。
Penguin =class("Penguin",Bird,Fish,PolarBear) --企鹅,是一种鸟,同时拥有鱼,北极熊的能力,完美
function Penguin:Fly() --企鹅不会飞,所以要重写它的Fly函数
print("I can'n Fly")
end
这样想想是不是很好啊,嗯,但是class的实现并不支持多重继承呀,好了,最重要的一步来了,我们就来改写class吧
function class(classname, super,...) --给class增加一个变参,支持多重继承
local superType = type(super)
local cls
--如果父类既不是函数也不是table则说明父类为空
if superType ~= "function" and superType ~= "table" then
superType = nil
super = nil
end
--如果父类的类型是函数或者是C对象
if superType == "function" or (super and super.__ctype == 1) then
-- inherited from native C++ Object
cls = {}
--如果父类是表则复制成员并且设置这个类的继承信息
--如果是函数类型则设置构造方法并且设置ctor函数
if superType == "table" then
-- copy fields from super
for k,v in pairs(super) do cls[k] = v end
cls.__create = super.__create
cls.super = super
else
cls.__create = super
cls.ctor = function() end
end
--设置类型的名称
cls.__cname = classname
cls.__ctype = 1
--定义该类型的创建实例的函数为基类的构造函数后复制到子类实例
--并且调用子数的ctor方法
function cls.new(...)
local instance = cls.__create(...)
-- copy fields from class to native object
for k,v in pairs(cls) do instance[k] = v end
instance.class = cls
instance:ctor(...)
return instance
end
else
--如果是继承自普通的lua表,则设置一下原型,并且构造实例后也会调用ctor方法
-- inherited from Lua Object
if super then
cls = {}
setmetatable(cls, {__index = super})
cls.super = super
else
cls = {ctor = function() end}
end
cls.__cname = classname
cls.__ctype = 2 -- lua
cls.__index = cls
function cls.new(...)
local instance = setmetatable({}, cls)
instance.class = cls
instance:ctor(...)
return instance
end
end
local interfaces={...}
for _,base in ipairs(interfaces) do
for k,v in pairs(base) do --遍历所有的接口类
if not cls[k] then
cls[k] = clone(v) --假如这些成员都不存在,就深copy到子类
end
end
end
return cls
end
在这里,class 增加了三个参数:第一个参数是类名,第二个是主基类,第三个是变长参数,我们可以称之类接口类。首先,主类会继承父类的所有接口,将它们copy到父类,然后,再遍历接口类的所有成员,假如这些成员不存在,就copy到子类,这样就完美在实现了多重继承了。
这里,当父类和接口类同时存在成员,只保留父类的,接口类同时存在的成员,按定义顺序,先定义的,会被copy到子类,后定义的不会。这样个规则解决了重名函数和变更的问题。