文档章节

对“tolua++导出C++子类后在Lua中无法添加新成员”这一问题的初步分析

SunLightJuly
 SunLightJuly
发布于 2014/05/10 03:28
字数 901
阅读 833
收藏 0
点赞 1
评论 5

一、问题的起因

    问题首先是在Quick-x中发现的,原因是希望为CCNode添加一个Lua自定义方法就会出错:

function CCNode:myMethod()
end

    运行错误提示是 [LUA ERROR] stack overflow,在Player上运行时甚至直接抛出异常提示框必须直接关闭程序。

    进一步调试,有以下结果:

    1.此问题只出现在导出的子类中,如CCObject就不会有问题,而包括CCNode在内所有继承CCObject的类就有问题

    2.并不仅仅是新加方法有问题,新加成员变量也是有问题的

    因此,这一问题可以描述为:tolua++导出的C++子类,在Lua中无法添加新成员。


二、问题的分析

    由于是无法添加新成员,首先考虑的是__newindex元方法是否有问题。

    分析tolua++的代码,可以看到在tolua_classevents函数中,将__newindex设置为了class_newindex_event函数:

static int class_newindex_event (lua_State* L)
{
    int t = lua_type(L,1);

    if (t == LUA_TUSERDATA)
    {
        //此处代码略去
    }
    else if (t== LUA_TTABLE)
    {
        module_newindex_event(L);
    }
    return 0;
}

    当CCObject和它的子类添加新成员时,这里的t值是LUA_TTABLE,因此会调用module_newindex_event函数:

static int module_newindex_event (lua_State* L)
{
    lua_pushstring(L,".set");
    lua_rawget(L,-4);
    if (lua_istable(L,-1))
    {
        //此处代码略去
    }
    /* call old newindex meta event */
    if (lua_getmetatable(L,1) && lua_getmetatable(L,-1))
    {
        lua_pushstring(L,"__newindex");
        lua_rawget(L,-2);
        if (lua_isfunction(L,-1))
        {
            lua_pushvalue(L,1);
            lua_pushvalue(L,2);
            lua_pushvalue(L,3);
            lua_call(L,3,0);
        }
    }
    lua_settop(L,3);
    lua_rawset(L,-3);
    return 0;
}

   可以看出这里是取metatable里的.set表,并对新的成员进行赋值。

   第一个判断,CCObject和它的子类都不会进入,没有影响。

   但第二个判断情况就不同了,CCObject不会进入,它的子类是会进入的。从代码写法上看,这里似乎是希望调用其父类的__newindex,但这样是很有问题的。

    首先现在这样的写法,取到的仍然是子类自己的__newindex,因此会再调用一次class_newindex_event函数,而class_newindex_event自然又会调用module_newindex_event,结果又回到了这段代码当中!这样,函数不断递归调用,永无休止,直到堆栈溢出为止,这就是出错为stack overflow的原因。

    其次我还没有想明白的是,即使是父类的__newindex,这里似乎也没有调用的必要。因为子类要是定义一个新成员是在父类里生效的话,那问题就大了。所以这里我认为直接调用lua_rawset应该就可以了。


三、临时解决方案

    基于以上分析,我认为问题就在于module_newindex_event的处理上。我尝试不调用module_newindex_event,而直接对新成员进行赋值操作,即修改class_newindex_event函数的相关代码如下:

    else if (t== LUA_TTABLE)
    {
//        module_newindex_event(L);
		lua_settop(L,3);
		lua_rawset(L,-3);
    }

   修改的这两句相当于在lua里面直接调用rawset对新成员进行赋值操作。

   修改后,在Lua中运行以下代码:

function CCNode:testFunc()
  print("----------CCNode.testFunc------Entry now!!!")
end

function MainScene:ctor()
    local s = display.newSprite("Logo.png", display.cx, display.cy)
    self:addChild(s)
    s:testFunc()
end

    上述代码是可以正常运行并得到预想中的输出的。

    不过目前这只是临时方案。我不知道tolua++原来这样写代码是不是另有原因。后面我将再仔细考虑清楚,这样的修改会不会有什么负作用。

(2014.5.30加注:quick-x的2.2.3版本目前已经采用了这一修改方案)

© 著作权归作者所有

共有 人打赏支持
SunLightJuly
粉丝 59
博文 15
码字总数 12480
作品 0
成都
加载中

评论(5)

SunLightJuly
SunLightJuly

引用来自“aodnshigfladgu”的评论

你好!七月大神!我试了一下网上tolua++后的cpp,player可用了,项目.so编译可过,但ant打包不行!可能的原因是什么呢?多谢!
打包错误如下:

at com.android.ant.DependencyHelper.resolveFullLibraryDependencies(Depen
dencyHelper.java:292)
从提示上看可能是打包时找不到依赖库
a
aodnshigfladgu
你好!七月大神!我试了一下网上tolua++后的cpp,player可用了,项目.so编译可过,但ant打包不行!可能的原因是什么呢?多谢!
打包错误如下:

at com.android.ant.DependencyHelper.resolveFullLibraryDependencies(Depen
dencyHelper.java:292)
a
aodnshigfladgu

引用来自“aodnshigfladgu”的评论

请问七月大神,quick如何集成Box2d?生成cpp后,如何在player中调用显示?

引用来自“SunLightJuly”的评论

集成box2d和集成其他模块并没有太大的区别,如果你集成过其他模块的话应该会很快的;如果没有,就需要参考一下其他模块的集成方法了。不过box2d应该是有很多人集成过的,还是有文章可以参考的。集成好以后,重新编译player就可以在player中使用了。
好的!谢谢回复!我去试一下!
SunLightJuly
SunLightJuly

引用来自“aodnshigfladgu”的评论

请问七月大神,quick如何集成Box2d?生成cpp后,如何在player中调用显示?
集成box2d和集成其他模块并没有太大的区别,如果你集成过其他模块的话应该会很快的;如果没有,就需要参考一下其他模块的集成方法了。不过box2d应该是有很多人集成过的,还是有文章可以参考的。集成好以后,重新编译player就可以在player中使用了。
a
aodnshigfladgu
请问七月大神,quick如何集成Box2d?生成cpp后,如何在player中调用显示?
C++灵魂所在之---多态的前世与今生

开头先送大家一句话吧: 众所周知,在20世纪80年代早期,C++在贝尔实验室诞生了,这是一门面向对象的语言,但它又不是全新的面向对象的语言,它是在传统的语言(C语言)进行面向对象扩展而来...

loving_forever_ ⋅ 2016/06/13 ⋅ 0

C语言编程学习程序解析:控制语句之goto语句

C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到...

小辰带你看世界 ⋅ 05/29 ⋅ 0

【C++程序设计技巧】NVI(Non-Virtual Interface )

在C++的程序设计中有一些设计开发的典型技巧需要整理讨论,在此抛砖引玉,为自己做积累,请高人也多多指教。 1.简介 在标准C++库中我们可以看到这样的一个现象: 6个公有虚函数,并且都是std...

老朱教授 ⋅ 2017/11/26 ⋅ 0

C语言/C++编程学习—神奇设计模式代码之群星

C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到...

小辰带你看世界 ⋅ 03/26 ⋅ 0

C/C++ 和 Python混合编程

链接:https://www.zhihu.com/question/23003213/answer/56121859 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 #include int main(int argc, char *...

sirius_0 ⋅ 04/21 ⋅ 0

C语言/C++编程学习强势之处的体现

C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到...

小辰带你看世界 ⋅ 05/12 ⋅ 0

C语言编程入门学习:C语言实现猜数字小游戏

C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到...

小辰带你看世界 ⋅ 05/30 ⋅ 0

BOOST.ASIO源码剖析(一)

前言 源码之前,了无秘密。 ——侯捷 Boost库是一个可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的开发引擎之一。Boost库由C++标准委员会库工作组成员发起,其中有些内容有...

moki_oschina ⋅ 04/11 ⋅ 0

C语言编程入门基础学习:替换字符串中的空格的实现

C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到...

小辰带你看世界 ⋅ 05/30 ⋅ 0

C语言/C++程序员编程基础学习代码训练

C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到...

小辰带你看世界 ⋅ 03/27 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

线程池

一、线程池:提供了一个线程队列,队列中保存着所有等待状态的线程。避免了创建与销毁额外开销,提高了响应的速度。 二、线程池的体系结构: java.util.concurrent.Executor : 负责线程的使用...

stars永恒 ⋅ 25分钟前 ⋅ 0

你值5K还是15K?实战案例,测测你的分析功力

本文源自陈老师遇到的真实案例。 老板说:“我们今年准备参加展会,做一年。以前我没参加过,没关系,这里有一份展会数据,你回去分析下哪些有价值,后边组织的时候有个指导”。现在你收到任...

加米谷大数据 ⋅ 27分钟前 ⋅ 0

中文转英文功能

package com.sysware.task.util;import net.sourceforge.pinyin4j.PinyinHelper;import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;import net.sourceforge.pinyin4j.for......

AK灬 ⋅ 28分钟前 ⋅ 0

JNI Java层类关联C/C++层的类

Android开发时,因为要实现某某功能,需要集成算法公司的算法库(so库),这就需要自己编写JNI。 通常这些库提供的接口可以概况成1、初始化 2、算法处理 3、释放 4、打印版本号 初始化后会返...

国仔饼 ⋅ 31分钟前 ⋅ 0

maven下载jar包改为阿里云的maven库

一:修改maven安装路径中conf文件夹下的setting.xml文件 <mirrors> <mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/......

夜醒者 ⋅ 31分钟前 ⋅ 0

电商用户行为分析大数据平台相关系列10-基础数据结构分析

电商用户行为分析大数据平台相关系列1-环境介绍 电商用户行为分析大数据平台相关系列2-HADOOP环境搭建 电商用户行为分析大数据平台相关系列3-HIVE安装 电商用户行为分析大数据平台相关系列4...

xiaomin0322 ⋅ 32分钟前 ⋅ 0

使用readLine()方法遇到的坑

下午玩 TCP/IP 的 Socket 通信时,使用 BufferedReader 的 readLine() 遇到了一个坑,现在终于解决了,特此记录下来。 程序很简单,客户段从控制台读取用户输入,然后发送至服务器端,主要代...

孟飞阳 ⋅ 33分钟前 ⋅ 0

基于Hadoop集群的Hive安装配置(Derby数据库)

Hive是一个数据仓库基础工具在Hadoop中用来处理结构化数据,提供简单的sql查询功能,可以将sql语句转换为MapReduce任务进行运行(具体的Hive架构大家自行搜索)。接下来主要讲下Hadoop集群下...

海岸线的曙光 ⋅ 34分钟前 ⋅ 0

CoreOS裸机iso安装和相关配置

裸机通过iso安装CoreOS,个人趟了很多坑,以下就是完整的从零开始部署和配置的过程,希望对大家有用。 一、安装CoreOS到硬盘 1. 准备Live iso镜像,制作好usb启动盘 Live iso下载地址 2. 搭建...

ykbj ⋅ 38分钟前 ⋅ 0

jquery控制表格锁列(转)

表格已经完成后新加的需求,要实现锁表格的第一列。很多带这种效果的都是js封装的框架或者具体某种框架的组件,不适用解决当前问题。作为后端开发又实在不熟样式,搜到了一个可以用的,虽然样...

刘昌鑫 ⋅ 41分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部