一开始打算用最简单的形式,就是如下:
function AIExecuteQueue:New() local o = {} setmetatable(o, self) self.__index = self o:init() return o end
一开始没啥问题,但后来逐渐发现问题。
首先我希望要有一个基类Base
Base:New里面绑定了一些事件。
AIExecuteQueue继承自事件
我一开始这么写:
AIExecuteQueue = Base:New()
然后调用AIExecuteQueue:New()
由于o的元表是AIExecuteQueue, 而AIExecuteQueue的元表是Base,看上去还不错,但实际并非如此。
还没有调用AIExecuteQueue:New的时候,Base:New已经被调用了,也就是说事件已经被绑定了,这和我们的预期完全不同。
后来看了云风的实现,发现是这样:
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非常有意思的方法,new本身其实就是构造了一个空table, 这个空table,访问这个table就是访问_class里面的实际table.
那这样怎么继承呢,如果指定了super,那么在访问实际表的时候,首先访问vtbl,如果vtbl里面没有,那么就会访问vtbl的元表,也就是super里面的key,同时还会把这个值拷贝到vtbl中,加快访问速度。
这样反过来看我们的一开始的设计问题,在定义New的时候,生成空tabel a, 让a的元表指向AIExecuteQueue. 然后由于AIExecuteQueue继承自base 我们需要让AIExecuteQueue的元表指向base
function AIExecuteQueue:New() local o = {} setmetatable(o, self) self.__index = self setmetatable(AIEcecuteQueue, Base)
AIExecuteQueue.__index = Base
return oend
self.super.init(self,xxx)
虽然蛋疼 但暂时也没有更好的办法了
最近发现一个新的问题,self.super不支持递归调用,就是C继承B,继承A,那么c.usper.init()并不会调用A.init()
于是修改如下:
--- --- Created by yxriyin. --- DateTime: 2017/12/28 16:05 --- local _class={} function CallBaseFunc() end function Class(super, o) local class_type={} class_type.ctor=false class_type.super=super class_type.New=function(...) local obj={} setmetatable(obj,{ __index=_class[class_type] }) 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 return obj end local vtbl= o or {} vtbl.super = super _class[class_type]=vtbl setmetatable(class_type,{__newindex= function(t,k,v) vtbl[k]=v end, __index = vtbl, }) if super then setmetatable(vtbl,{__index= function(t,k) local ret=_class[super][k] vtbl[k]=ret return ret end }) function class_type.callBase(self, f, ...) if not self.virtualList then self.virtualList = {} end local base = self.super if self.virtualList[f] then base = self.virtualList[f] else local base1 = self local base2 = base while base1 and base2 do if base1[f] == base2[f] then base = base.super base2 = base2.super base1 = base1.super else break end end end self.virtualList[f] = base.super local result = base[f](self, ...) self.virtualList[f] = nil return result end end return class_type end
这里模拟了一个最简单的虚表的实现
这样子就是self:callBase("method")来实现调用子类的函数,而且支持递归调用
没有评论:
发表评论