从Objective-C转战C++ Android平台开发实践(C++/Java)
是否使用虚拟方法
- 最好在不用“virtual”关键字的情况下声明所有cpp成员方法
- 但是在写CPP头文件时,请检查有没有父类的方法被当前的工作覆盖。如果有,请确保将这些方法改为虚拟方法。
- 如果从父类继承了一个虚拟方法,确保这个方法可以继承“virtual”(虚拟)关键字
public/protected/private方法介绍
- 默认情况下,将所有成员方法声明为“public”(公共)
- 如果以下任意条件满足,方法必须为“private”:该方法在.m文件被声明;该方法位于“private”范畴
public/protected/private成员变量
- 声明所有成员变量为“protected”,没有其他选择。
两阶段构造
如何
- 第一阶段:在构造器初始化列表中设置所有成员变量的默认值。但不要在构造器中编写任何逻辑init(初始化)。
- 第二阶段:在“CMyClass* init(...)”函数中编写逻辑init(初始化)。如果初始化失败会返回NULL。
为什么
- 我们决定在C++中不再使用捕获异常机制(try-catch exception mechanism)。这是为了减少足迹和二进制大小。因此在C++构造中发生的任何异常都不会被报告给调用者。
时间
- 两阶段构造并不是在每个类中都一定要进行,只是在那些存在初始化逻辑步骤的类中进行。换言之,在构造器中编写逻辑初始化是禁止的,这种情况可能会返回错误。
调用者须知
- 如何你调用的类有“bool init(...)”函数,请在构造之后立即调用该函数。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | #define CCX_BREAK_IF(cond) if(cond) break;#define CCX_SAFE_DELETE(p)  if(p) {delete (p); (p) = NULL;}// declarationclassCCar{public:    CCar();    boolinit();    virtual~CCar();protected:    CEngine* m_pEngine;    boolm_bStarted;    boolm_bLocked;};// 1st-phase construction// only set the default value & alloc memoryCCar::CCar():m_pEngine(newCEngine),m_bStarted(false),m_bLocked(true){    printf("CCar constructor\n");}// 2st-phase construction// do logical initializationboolCCar::init(){    boolbRet = false;    do    {        m_bLocked = false;        CCX_BREAK_IF( !m_pEngine );        // defensive        CCX_BREAK_IF( !m_pEngine->start() );    // logic        // success        bRet = true;    } while(0);    printf("CCar init\n");    returnbRet;}// destructionCCar::~CCar(){    if(m_pEngine)    {        deletem_pEngine;        m_pEngine = NULL;    }    printf("CCar destructor\n");}// invokerint_tmain(intargc, _TCHAR* argv[]){    // in heap    CCar* pCar = newCCar;    if(!pCar->init())    {        CCX_SAFE_DELETE(pCar);    }    // in stack    CCar car;    if(!car.init())    {        // do sth.    }    return0;} | 
下载样本代码请参见附件“TwoPhaseConstruction.zip”。该项目已经在Win32环境+VS2008测试过。
objc属性
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | /** CCX_PROPERTY_READONLY is used to declare a protected variable.    We can use get method to read the variable.    @param varType : the type of variable.    @param varName : variable name.    @param funName : "get + funName" is the name of the get method.    @warning : The get method is a public virtual function, you should override it first.            The variables and methods declared after CCX_PROPERTY_READONLY are all public.            If you need protected or private, please declare.*/#define CCX_PROPERTY_READONLY(varType, varName, funName)\    protected: varType varName;\    public: virtualvarType get##funName(void);/** CCX_PROPERTY is used to declare a protected variable.    We can use get method to read the variable, and use the set method to change the variable.    @param varType : the type of variable.    @param varName : variable name.    @param funName : "get + funName" is the name of the get method.                     "set + funName" is the name of the set method.    @warning : The get and set methods are public virtual functions, you should override them first.            The variables and methods declared after CCX_PROPERTY are all public.            If you need protected or private, please declare.*/#define CCX_PROPERTY(varType, varName, funName)\    protected: varType varName;\    public: virtualvarType get##funName(void);\    public: virtualvoidset##funName(varType var);/** CCX_SYNTHESIZE_READONLY is used to declare a protected variable.    We can use get method to read the variable.    @param varType : the type of variable.    @param varName : variable name.    @param funName : "get + funName" is the name of the get method.    @warning : The get method is a public inline function.            The variables and methods declared after CCX_SYNTHESIZE_READONLY are all public.            If you need protected or private, please declare.*/#define CCX_SYNTHESIZE_READONLY(varType, varName, funName)\    protected: varType varName;\    public: inlinevarType get##funName(void){ returnvarName; }/** CCX_SYNTHESIZE is used to declare a protected variable.    We can use get method to read the variable, and use the set method to change the variable.    @param varType : the type of variable.    @param varName : variable name.    @param funName : "get + funName" is the name of the get method.                     "set + funName" is the name of the set method.    @warning : The get and set methods are public  inline functions.            The variables and methods declared after CCX_SYNTHESIZE are all public.            If you need protected or private, please declare.*/#define CCX_SYNTHESIZE(varType, varName, funName)\    protected: varType varName;\    public: inlinevarType get##funName(void){ returnvarName; }\    public: inlinevoidset##funName(varType var){ varName = var; } | 
id
Objc中一些函数会返回“ID“,在转换成CPP后就会返回“bool”。在Objc中,你可以像“[[MyClass alloc] init] autorelease]”一样编写代码,无需在意初始化是否失败返回NULL。在这种情况下“[nil autorelease]”不会使程序崩溃。但是在CPP中,返回“bool”是为了防止开发人员编写“pClass = (new MyClass())->init()->foo()”。如果初始化失败返回NULL,在CPP中“null->fool()”会崩溃然后跳出程序。另一方面,如果“foo()”返回值不是“MyClass*”,例如返回“bool”,那调用者就会失去“new MyClass”的指针,然后无法从堆栈(heap)中删除指针。这就会很危险。
| 1 2 | @interface CTest-(id) foo(); | 
以上代码必须转换为
| 1 2 3 4 | classCTest{    boolfoo();} | 
目的
在Cocos2dx场景中点击按钮,即可向本地平台Java弹出对话框发送信息。详见本文。
指令
你需要对项目执行几次include(包含)指令,本人已创建一个在线Repo库,根据开发环境种类分成了几个部分。请确保include(包含)了所有C++和Java的文件。在线Repo连接如下:EasyNDK。
从C++包含
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include "NDKHelper.h" // The button click method of Cocos2dxvoidHelloWorld::menuCloseCallback(CCObject* pSender){    // Register a selector in a global space    // So that when our native environment will call the method with the string    // It can respond to the selector    // Note : Group name is there for ease of removing the selectors    NDKHelper::AddSelector("HelloWorldSelectors",                           "SampleSelector",                           callfuncND_selector(HelloWorld::SampleSelector),                           this);    // Making parameters for message to be passed to native language    // For the ease of use, i am sending the method to be called name from C++    CCDictionary* prms = CCDictionary::create();    prms->setObject(CCString::create("SampleSelector"), "to_be_called");    // Finally call the native method in current environment    SendMessageWithParams(string("SampleSelector"), prms);}// A selector that will respond to us, when native language will call itvoidHelloWorld::SampleSelector(CCNode *sender, void*data){    CCLog("Called from native environment");}// Destructor to remove all the selectors which are grouped as HelloWorldSelectorsHelloWorld::~HelloWorld(){    // Remove the associated selector group from the global space,    // Because we are destroying this instance    NDKHelper::RemoveSelectorsInGroup("HelloWorldSelectors");} | 
从Java包含:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | /** Called when the activity is first created. */publicvoidonCreate(Bundle savedInstanceState){    super.onCreate(savedInstanceState);    // In the main Activity, assigning that activity as a receiver for C++ messages    AndroidNDKHelper.SetNDKReciever(this);}// Implement the method to be called for a message from C++// Be sure to name the method to be of the same string as you will pass from C++// Like we passed "SampleSelector" from C++, that is why created this methodpublicvoidSampleSelector(JSONObject prms){    Log.v("SampleSelector", "purchase something called");    Log.v("SampleSelector", "Passed params are : "+ prms.toString());    String CPPFunctionToBeCalled = null;    try    {        CPPFunctionToBeCalled = prms.getString("to_be_called");    }    catch(JSONException e)    {        // TODO Auto-generated catch block        e.printStackTrace();    }    AlertDialog.Builder builder = newAlertDialog.Builder(this);    builder.setMessage("This is a sample popup on Android").    setTitle("Hello World!").    setNeutralButton("OK", null).show();    // Send C++ a message with paramerts    // C++ will recieve this message, only if the selector list will have a method    // with the string we are passing    AndroidNDKHelper.SendMessageWithParameters(CPPFunctionToBeCalled, null);} | 
注意 若连接其他SDK,你可以参考相关SDK的Java指南并分别实施消息传递机制从Cocos2d-x进行调用。本人通过这种方法已经实现了AppCircle、Flurry以及其他很多SDK。 拥有完整源码的样本项目可从网上下载:Sample Android Project。 祝编程愉快!
从Objective-C转战C++ Android平台开发实践(C++/Java)的更多相关文章
- 最初程序员的思维“修炼”之四——Android平台开发的“强制关闭”解决思路
		我和我的朋友参加一个比赛——物联网应用技能大赛,这个大赛所要求的技能有,硬件技术,Android平台开发技术,.NET平台开发技术,所以这是一个团队合作的比赛,基本上没有人能同时掌握这三种技术(在校生 ... 
- Android游戏开发实践(1)之NDK与JNI开发03
		Android游戏开发实践(1)之NDK与JNI开发03 前面已经分享了两篇有关Android平台NDK与JNI开发相关的内容.以下列举前面两篇的链接地址,感兴趣的可以再回顾下.那么,这篇继续这个小专 ... 
- Android游戏开发实践(1)之NDK与JNI开发01
		Android游戏开发实践(1)之NDK与JNI开发01 NDK是Native Developement Kit的缩写,顾名思义,NDK是Google提供的一套原生Java代码与本地C/C++代码&q ... 
- Android软件安全开发实践(下)
		Android开发是当前最火的话题之一,但很少有人讨论这个领域的安全问题.本系列将分两期,探讨Android开发中常见的安全隐患和解决方案.第一期将从数据存储.网络通信.密码和认证策略这三个角度,带你 ... 
- Android游戏开发实践(1)之NDK与JNI开发02
		Android游戏开发实践(1)之NDK与JNI开发02 承接上篇Android游戏开发实践(1)之NDK与JNI开发01分享完JNI的基础和简要开发流程之后,再来分享下在Android环境下的JNI ... 
- Android游戏开发实践(1)之NDK与JNI开发04
		Android游戏开发实践(1)之NDK与JNI开发04 有了前面几篇NDK与JNI开发相关基础做铺垫,再来通过代码说明下这方面具体的操作以及一些重要的细节.那么,就继续NDK与JNI的学习总结. 作 ... 
- Android NDK开发 JNI操作java构造方法,普通方法,静态方法(七)
		Android NDK开发 JNI操作java普通.静态.构造方法 1.Jni实例化一个Java类的实例jobject 1.通过FindClas( ),获取Java类的的jclass 2.通过GetM ... 
- Android平台dalvik模式下java Hook框架ddi的分析(2)--dex文件的注入和调用
		本文博客地址:http://blog.csdn.net/qq1084283172/article/details/77942585 前面的博客<Android平台dalvik模式下java Ho ... 
- 调研Android平台开发环境的发展演变
		Android是Google推出的开源手机操作系统,主要以开发应用为主,要进行Android开发首先得搭建好开发平台.最近在搭建Android的开发环境,发现往往一个小问题都能花费你大半天时间,从刚开 ... 
随机推荐
- [转发]Linux的系统调用宏
			原来在linux/include/linux/syscalls.h 中定义了如下的宏: 复制代码#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1 ... 
- 过滤字符串的Html标记 c#函数 .
			.public static string StripHTML(string strHtml) . { . string[] aryReg ={ . @"<script[^>]* ... 
- Oracle11g的exp导出空表提示EXP-00011: 不存在
			刚lg问我11g无法导出空表,实验了下,果真如此. 原因:11g默认创建一个表时不分配segment,只有在插入数据时才会产生(当然也可以强制分配),以节省磁盘空间. 对于已经存在的空表解决办法: 就 ... 
- Linux服务器间文件传输
			利用scp传输文件 1.从服务器下载文件 scp username@servername:/path/filename /tmp/local_destination 例如scp codinglog@1 ... 
- my.conf 配置编码为utf-8
			MySQL基础配置之mysql的默认字符编码的设置(my.ini设置字符编码) MySQL的默认编码是Latin1,不支持中文,那么如何修改MySQL的默认编码呢,下面以设置UTF-8为例来说明. M ... 
- 9月20日下午JavaScript函数--递归
			例题1:公园里有200个桃子,猴子每天吃掉一半以后扔掉一个,问6天以后还剩余多少桃子? var sum = 200; for(var i= 0;i<6;i++) { sum = parseInt ... 
- Java基本语法笔记
			1. 基本格式: public class HelloWprdApp { public static void main(String[] args) { // TODO Auto-ge ... 
- Unlink of file '.git/objects/pack/pack-***.pack' failed. Should I try again? (y/n) (转)
			git pull的时候遇到 Unlink of file '.git/objects/pack/pack-***.pack' failed. Should I try again? (y/n) y 于 ... 
- 将图片部署在tomcat/iportWork/uploadFiles中
			将图片部署在tomcat/iportWork/uploadFiles中 1.在将运行的tomcat目录下创建个二级目录iportWork\uploadFiles,如下图: 
- pch
			#define kWeakSelf(weakSelf) __weak __typeof(self)weakSelf = self; #ifndef __OPTIMIZE__#define NSLog( ... 
