cocos-lua 多重继承的iskindof的BUG

cocos-lua的iskindof在多重继承时有一个BUG,如下:

    local A=class("ClassA")
    local B=class("ClassB",A)
    local binst= B.new()
    print(   iskindof(binst,"ClassA")  )

ClassB继承自ClassA,因此B的对象理应也是ClassA的对象。但是输出结果却是false. (如果你已经知道这个BUG,想知道怎么解决,直接跳到最后;如果你想看是什么原因,则往下看。)

iskindof源码

那么就要看下iskindof的代码了。源码如下:

    function iskindof(obj, classname)
        local t = type(obj)
        if t ~= "table" and t ~= "userdata" then return false end

        local mt
        if t == "userdata" then
            if tolua.iskindof(obj, classname) then return true end
            mt = tolua.getpeer(obj)
        else       
            mt = getmetatable(obj)   --我传进来的binst是走到这个分支
        end
        if mt then
            --最后调用这个,mt就是binst的metatable,classname就是传进来的"ClassA"
            return iskindof_(mt, classname) 
        end
        return false
    end

略有点复杂,iskindof流程大概是先判断传进来的obj什么类型,如果是table类型的则取它的元表metatable;如果是userdata类型的,则用tolua的方式来判断。

我们的传进去的是binst,是个table类型;所以执行getmetatable。然后再去调用iskindof_。单纯按照kindof这个函数的意图来讲,这个貌似没什么问题:“传进来如果是个table,那么我们就去查它的metatable是个什么类就可以了。”

那再看看最后一步iskindof_是个什么函数,源码如下:

local iskindof_
iskindof_ = function(cls, name)
    local __index = rawget(cls, "__index")
    if type(__index) == "table" and rawget(__index, "__cname") == name then return true end

    if rawget(cls, "__cname") == name then return true end
    local __supers = rawget(cls, "__supers")  --获取的__supers为空
    if not __supers then return false end
    for _, super in ipairs(__supers) do
        if iskindof_(super, name) then return true end
    end
    return false
end

(程序中rawget意思是只找当前表里的内容,避免lua自动去找这个表的元表的内容)

其大致的流程是:
1.先找cls的__index,看看__index的类名是不是我们要的。
2.如果不是,看看cls本身是不是我们要的。
3.如果不是,那么我们看看cls的父类有没有我们要的。找父类的过程是个迭代的过程,只要找到了,则return true;没有找到,则继续找下一个父类。

按照这个函数的意思,如果当前类找不到类名,会去找父类。但是我运行了一下,当把binst的元表传进去之后,__supers为空!这显然是不对的,binst明明是有父类的,怎么会没有__supers呢?肯定哪里错误了。
所以接下来我们要解决的问题是,也是本文的中心:

为什么iskindof\_找不到binst的__supers?

不过,我承认iskindof_这个函数有点不好消化,因为一下子来了那么多新的域,什么__index、__supers、__cname等等。这就涉及到class的内部结构了。
再粘一下class的源码,不要被吓到。吓到了,直接跳过看我的研究成果吧。

class的结构

function class(classname, ...)
    local cls = {__cname = classname}

    local supers = {...}
    for _, super in ipairs(supers) do
        local superType = type(super)
        assert(superType == "nil" or superType == "table" or superType == "function",
 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值