Cocos2d-X lua binding C++类的RTTI

在用Cococs2d-X的lua binding时,遇到了需要RTTI的时候,也就是运行时类型识别,这点对于lua类来说还是很容易做到的,可以参考引擎lua framework中cocos/cocos2d/functions.lua中的function iskindof(obj, classname),不过,这个函数的递归实现函数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
    -- By K-Res: should use __index instead of cls!
--    local __supers = rawget(cls, "__supers")
    local __supers = rawget(__index, "__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

然而,当遇到需要对binding到lua的native class进行RTTI就有些麻烦了,可以看到借助tolua过去的lua对象是usertable挂metatable实现的,而metatable中也没有可以用lua类(确切的说是模拟class行为的table)的RTTI方式,因为需要查找的一些__cname等meta成员并不存在,作为class标识的只有一个.isclass的bool值,看了下binding实现的原生代码,发现在不添加额外元表信息的前提下获取class名称是需要用到LUA_REGISTRYINDEX这个只能由原生代码获取到的lua全局信息注册表,于是放弃了通过lua代码实现绑定类类型识别的想法,转而使用原生函数实现了个简单的获取binding时设置的本类class名方法,暂时实现了本对象所属类识别的功能:

int push_table_instance(lua_State* L, int lo) {

	if (lua_istable(L, lo)) {

		lua_pushstring(L, ".c_instance");
		lua_gettable(L, lo);
		if (lua_isuserdata(L, -1)) {

			lua_replace(L, lo);
			return 1;
		}
		else {

			lua_pop(L, 1);
			return 0;
		};
	}
	else {
		return 0;
	};

	return 0;
};

static int bsGetBindingClassName(lua_State* L)
{
	// A class table must use metatable to get it's type now. 2014.6.5 by SunLightJuly
	if (!lua_isuserdata(L, -1)) {
		if (!push_table_instance(L, -1)) {
			return 0;
		};
	};
	{
		/* check if it is of the same type */
		int r;
		const char *tn;
		if (lua_getmetatable(L, -1))        /* if metatable? */
		{
			lua_rawget(L, LUA_REGISTRYINDEX);  /* get registry[mt] */
			tn = lua_tostring(L, -1);
			lua_pushstring(L, tn);
			return 1;
		}
	}

	return 0;                   /* number of results */
}
...
	lua_register(tolua_S, "bsGetBindingClassName", bsGetBindingClassName);
...

使用如下:

    print("============>", bsGetBindingClassName(cc.Node:create()))
    print("============>", bsGetBindingClassName(ccui.ImageView:create()))
    print("============>", bsGetBindingClassName(ccui.Button:create()))
...
[LUA-print] ============>	cc.Node
[LUA-print] ============>	ccui.ImageView
[LUA-print] ============>	ccui.Button

PS:只是简单实现了本类类名的方法,理论上递归下父类类型应该可以做到真正意义上的RTTI。

博主友情提示:

如您在评论中需要提及如QQ号、电子邮件地址或其他隐私敏感信息,欢迎使用>>博主专用加密工具v3<<处理后发布,原文只有博主可以看到。