问题记录:cocos2dx-C++静态成员函数的使用问题
2013-08-28 14:39
465 查看
/**
Time: 2013-0818
Requirements:
1. 解决C++使用静态成员函数,编译后运行出错的问题;
*/
情景:有class A,它只有一个共享方法生成一个实例,又有一个class B,它引用class A,但是是通过以下方法引用,请看下面
A.cpp文件大致内容:
B.cpp文件大致内容:
问题为:static A *pA = A::share();// 获取A的对象指针保存到文件域的静态变量pA中,编译没有问题,在android加载该*.so时就会出错;
针对该问题,我进行了几项测试:
1. 将class B 中的//static A *pA = A::share();// 该语句注释,重新编译运行,结果:成功加载*.so,apk顺利运行;
2.将class A 的构造函数A()的//someMethod()调用语句注释,结果:也没有问题了;
3.将在class B内部使用static A *pA = A::share();// ,结果:也没有问题;
4.使用windows平台,不进行任何代码修改,结果:完全没有问题;
5.将class B 中的A *pA = A::share(); 改为了非static,重新编译运行,结果:出错;
6.将class A中someMethod()调用改为直接的函数代码,结果:出错;
7.将class A中A()中引用该类的成员变量的语句注释掉,保留someMethod()的代码,结果:出错;
8. 经过2,6,7共三个测试,我发现我的A()里引用了cocos2dx的CCFileUtils::sharedFileUtils()->getWriteablePath()语句,所以我灵感来了,直接把它给注释掉,结果:没有出现问题了;
9. 回退8~1的测试,结果,所有问题都出现在cocos2dx的CCFileUtils::sharedFileUtils()->getWriteablePath()语句身上;把它注释掉,结果:1~8项测试都完全没有问题;
结论,:(个人认为的结论)
1. 本来以为是C++语法问题,结果证明不是,起初我还以为自己解决的系统编译器语法问题而高兴,但是想想不对啊,标准的东西不应该因编译器不同而轻易出错,后来发现是我自己使用问题,万幸;
2. 关键:如果在全局里使用了C++调用java层的代码,那么就要注意了,C++调用的方法所属的类有没有在C++之前创建完成并可以调用,如果可以,那么就没有问题,如果不可以,那么就可能出现我上面的错误了,一直加载*.so失败,因为so里的C++调用了一个不可用的java方法,怎么可能不挂掉;
3. 为了更接近事实,我跟踪去看了CCFileUtils::sharedFileUtils()->getWriteablePath()调用java层的代码,以下代码出自《cocos2dx2.0.4引擎的代码库》:
C++调用java层的代码:
由上面可见,C++调用的是java层的静态方法,理论上不应该会出现问题,原因可能是虽然同是静态方法,但是加载也有顺序,顺序不对,没有初始化,调用也是会出错的,C++全局函数的调用可能比Cocos2dxHelper加载初始化前还要早,那么就会出错,后来我把全局static A *pA = A::share();代码注释掉,把它放在一个全局类内部进行初始化,就不会出现问题了;
本人对java和android只有基本理解,没有深入,其中andoid启动apk的逻辑顺序不是很懂,希望高手能解释一下;
Time: 2013-0818
Requirements:
1. 解决C++使用静态成员函数,编译后运行出错的问题;
*/
情景:有class A,它只有一个共享方法生成一个实例,又有一个class B,它引用class A,但是是通过以下方法引用,请看下面
// Begin A.h codes #ifndef __A__H___ #define __A__H___ class A { public: ~A(); static A *share(){ if ( NULL == m_pA ) { m_pA = new A(); } return m_pA; }; void someMethod(); protected: A(); private: static A *m_pA; }; #endif // END A.h codes
A.cpp文件大致内容:
// Begin A.cpp codes #include "A.h" A* A::m_pA = NULL; A::A() { someMethod(); } void A::someMethod() { // do some work string strFilePath = CCFileUtils::sharedFileUtils()->getWriteablePath(); // do some work } // End A.cpp codes
B.cpp文件大致内容:
// Begin B.cpp codes static A *pA = A::share();// 获取A的对象指针保存到文件域的静态变量pA中,编译没有问题,在android加载该*.so时就会出错 // other method of B ... // End B.cpp codes
问题为:static A *pA = A::share();// 获取A的对象指针保存到文件域的静态变量pA中,编译没有问题,在android加载该*.so时就会出错;
针对该问题,我进行了几项测试:
1. 将class B 中的//static A *pA = A::share();// 该语句注释,重新编译运行,结果:成功加载*.so,apk顺利运行;
2.将class A 的构造函数A()的//someMethod()调用语句注释,结果:也没有问题了;
3.将在class B内部使用static A *pA = A::share();// ,结果:也没有问题;
4.使用windows平台,不进行任何代码修改,结果:完全没有问题;
5.将class B 中的A *pA = A::share(); 改为了非static,重新编译运行,结果:出错;
6.将class A中someMethod()调用改为直接的函数代码,结果:出错;
7.将class A中A()中引用该类的成员变量的语句注释掉,保留someMethod()的代码,结果:出错;
8. 经过2,6,7共三个测试,我发现我的A()里引用了cocos2dx的CCFileUtils::sharedFileUtils()->getWriteablePath()语句,所以我灵感来了,直接把它给注释掉,结果:没有出现问题了;
9. 回退8~1的测试,结果,所有问题都出现在cocos2dx的CCFileUtils::sharedFileUtils()->getWriteablePath()语句身上;把它注释掉,结果:1~8项测试都完全没有问题;
结论,:(个人认为的结论)
1. 本来以为是C++语法问题,结果证明不是,起初我还以为自己解决的系统编译器语法问题而高兴,但是想想不对啊,标准的东西不应该因编译器不同而轻易出错,后来发现是我自己使用问题,万幸;
2. 关键:如果在全局里使用了C++调用java层的代码,那么就要注意了,C++调用的方法所属的类有没有在C++之前创建完成并可以调用,如果可以,那么就没有问题,如果不可以,那么就可能出现我上面的错误了,一直加载*.so失败,因为so里的C++调用了一个不可用的java方法,怎么可能不挂掉;
3. 为了更接近事实,我跟踪去看了CCFileUtils::sharedFileUtils()->getWriteablePath()调用java层的代码,以下代码出自《cocos2dx2.0.4引擎的代码库》:
C++调用java层的代码:
const char* getPackageNameJNI() { JniMethodInfo t; if (JniHelper::getStaticMethodInfo(t, CLASS_NAME, "getCocos2dxPackageName", "()Ljava/lang/String;")) { jstring str = (jstring)t.env->CallStaticObjectMethod(t.classID, t.methodID); t.env->DeleteLocalRef(t.classID); CCString *ret = new CCString(JniHelper::jstring2string(str).c_str()); ret->autorelease(); t.env->DeleteLocalRef(str); return ret->m_sString.c_str(); } return 0; }
java层的部分代码:
private static Cocos2dxMusic sCocos2dMusic; private static Cocos2dxSound sCocos2dSound; private static AssetManager sAssetManager; private static Cocos2dxAccelerometer sCocos2dxAccelerometer; private static boolean sAccelerometerEnabled; private static String sPackageName; private static Cocos2dxHelperListener sCocos2dxHelperListener; // =========================================================== // Constructors // =========================================================== public static void init(final Context pContext, final Cocos2dxHelperListener pCocos2dxHelperListener) { final ApplicationInfo applicationInfo = pContext.getApplicationInfo(); Cocos2dxHelper.sCocos2dxHelperListener = pCocos2dxHelperListener; Cocos2dxHelper.sPackageName = applicationInfo.packageName; Cocos2dxHelper.nativeSetApkPath(applicationInfo.sourceDir); Cocos2dxHelper.nativeSetExternalAssetPath(Cocos2dxHelper.getAbsolutePathOnExternalStorage(applicationInfo, "assets/")); Cocos2dxHelper.sCocos2dxAccelerometer = new Cocos2dxAccelerometer(pContext); Cocos2dxHelper.sCocos2dMusic = new Cocos2dxMusic(pContext); Cocos2dxHelper.sCocos2dSound = new Cocos2dxSound(pContext); Cocos2dxHelper.sAssetManager = pContext.getAssets(); Cocos2dxBitmap.setContext(pContext); }
public static String getCocos2dxPackageName() { return Cocos2dxHelper.sPackageName; }
由上面可见,C++调用的是java层的静态方法,理论上不应该会出现问题,原因可能是虽然同是静态方法,但是加载也有顺序,顺序不对,没有初始化,调用也是会出错的,C++全局函数的调用可能比Cocos2dxHelper加载初始化前还要早,那么就会出错,后来我把全局static A *pA = A::share();代码注释掉,把它放在一个全局类内部进行初始化,就不会出现问题了;
本人对java和android只有基本理解,没有深入,其中andoid启动apk的逻辑顺序不是很懂,希望高手能解释一下;
相关文章推荐
- c++:静态成员变量和静态成员函数使用问题
- C++静态库中使用_declspec(dllexport) 不能导出函数的问题
- 关于c++中类静态成员函数可能破坏类封装性的问题
- C++ 静态成员函数使用不需要声明
- C++静态成员变量和静态成员函数的使用方法总结
- C++中静态成员函数访问成员变量问题
- C++中静态成员函数访问成员变量问题
- C++静态成员变量和静态成员函数的使用方法总结
- C++中静态成员函数访问成员变量问题
- C++静态成员变量和静态成员函数使用总结
- 关于C++静态成员函数访问非静态成员变量的问题
- C++静态成员(静态成员变量、静态成员函数)与正常成员互相调用的权限问题
- C++ 静态成员函数可以使用类内的枚举值
- C++静态成员变量和静态成员函数使用总结
- C++使用线程函数pthread_create时,调用的成员函数要定义为静态成员函数
- C++中使用非静态成员函数代替全局函数
- C++使用静态成员函数
- C++中静态成员函数访问成员变量问题
- C++中静态成员函数的常量型问题
- 关于C++静态成员函数访问非静态成员变量的问题