是否使用虚拟方法

  1. 最好在不用“virtual”关键字的情况下声明所有cpp成员方法
  2. 但是在写CPP头文件时,请检查有没有父类的方法被当前的工作覆盖。如果有,请确保将这些方法改为虚拟方法。
  3. 如果从父类继承了一个虚拟方法,确保这个方法可以继承“virtual”(虚拟)关键字

public/protected/private方法介绍

  1. 默认情况下,将所有成员方法声明为“public”(公共)
  2. 如果以下任意条件满足,方法必须为“private”:该方法在.m文件被声明;该方法位于“private”范畴

public/protected/private成员变量

  1. 声明所有成员变量为“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;}
 
// declaration
class CCar
{
public:
    CCar();
    bool    init();
    virtual ~CCar();
 
protected:
    CEngine* m_pEngine;
    bool     m_bStarted;
    bool     m_bLocked;
};
 
// 1st-phase construction
// only set the default value & alloc memory
CCar::CCar()
:m_pEngine(new CEngine)
,m_bStarted(false)
,m_bLocked(true)
{
    printf("CCar constructor\n");
}
 
// 2st-phase construction
// do logical initialization
bool CCar::init()
{
    bool bRet = 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");
    return bRet;
}
 
// destruction
CCar::~CCar()
{
    if (m_pEngine)
    {
        delete m_pEngine;
        m_pEngine = NULL;
    }
 
    printf("CCar destructor\n");
}
 
// invoker
int _tmain(int argc, _TCHAR* argv[])
{
    // in heap
    CCar* pCar = new CCar;
    if (!pCar->init())
    {
        CCX_SAFE_DELETE(pCar);
    }
 
    // in stack
    CCar car;
    if (!car.init())
    {
        // do sth.
    }
 
    return 0;
}

下载样本代码请参见附件“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: virtual varType 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: virtual varType get##funName(void);\
    public: virtual void set##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: inline varType get##funName(void){ return varName; }
 
/** 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: inline varType get##funName(void){ return varName; }\
    public: inline void set##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
class CTest
{
    bool foo();
}

目的

在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 Cocos2dx
void HelloWorld::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 it
void HelloWorld::SampleSelector(CCNode *sender, void *data)
{
    CCLog("Called from native environment");
}
 
// Destructor to remove all the selectors which are grouped as HelloWorldSelectors
HelloWorld::~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. */
public void onCreate(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 method
public void SampleSelector(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 = new AlertDialog.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)的更多相关文章

  1. 最初程序员的思维“修炼”之四——Android平台开发的“强制关闭”解决思路

    我和我的朋友参加一个比赛——物联网应用技能大赛,这个大赛所要求的技能有,硬件技术,Android平台开发技术,.NET平台开发技术,所以这是一个团队合作的比赛,基本上没有人能同时掌握这三种技术(在校生 ...

  2. Android游戏开发实践(1)之NDK与JNI开发03

    Android游戏开发实践(1)之NDK与JNI开发03 前面已经分享了两篇有关Android平台NDK与JNI开发相关的内容.以下列举前面两篇的链接地址,感兴趣的可以再回顾下.那么,这篇继续这个小专 ...

  3. Android游戏开发实践(1)之NDK与JNI开发01

    Android游戏开发实践(1)之NDK与JNI开发01 NDK是Native Developement Kit的缩写,顾名思义,NDK是Google提供的一套原生Java代码与本地C/C++代码&q ...

  4. Android软件安全开发实践(下)

    Android开发是当前最火的话题之一,但很少有人讨论这个领域的安全问题.本系列将分两期,探讨Android开发中常见的安全隐患和解决方案.第一期将从数据存储.网络通信.密码和认证策略这三个角度,带你 ...

  5. Android游戏开发实践(1)之NDK与JNI开发02

    Android游戏开发实践(1)之NDK与JNI开发02 承接上篇Android游戏开发实践(1)之NDK与JNI开发01分享完JNI的基础和简要开发流程之后,再来分享下在Android环境下的JNI ...

  6. Android游戏开发实践(1)之NDK与JNI开发04

    Android游戏开发实践(1)之NDK与JNI开发04 有了前面几篇NDK与JNI开发相关基础做铺垫,再来通过代码说明下这方面具体的操作以及一些重要的细节.那么,就继续NDK与JNI的学习总结. 作 ...

  7. Android NDK开发 JNI操作java构造方法,普通方法,静态方法(七)

    Android NDK开发 JNI操作java普通.静态.构造方法 1.Jni实例化一个Java类的实例jobject 1.通过FindClas( ),获取Java类的的jclass 2.通过GetM ...

  8. Android平台dalvik模式下java Hook框架ddi的分析(2)--dex文件的注入和调用

    本文博客地址:http://blog.csdn.net/qq1084283172/article/details/77942585 前面的博客<Android平台dalvik模式下java Ho ...

  9. 调研Android平台开发环境的发展演变

    Android是Google推出的开源手机操作系统,主要以开发应用为主,要进行Android开发首先得搭建好开发平台.最近在搭建Android的开发环境,发现往往一个小问题都能花费你大半天时间,从刚开 ...

随机推荐

  1. 利用POI 技术动态替换word模板内容

    项目中需要实现一个功能,动态替换给定模板里面的内容,生成word文档提供下载功能. 中间解决了问题有: 1.页眉的文档logo图片解决,刚开始的时候,HWPFDocument 对象无法读取图片对象(已 ...

  2. wcf第1步

    添加System.ServiceModel 引用 Wcf 服务端 class Program { static void Main(string[] args) { ServiceHost host ...

  3. Linux 下 Oracle 内核参数优化

    数据库的性能优化涉及到整个数据库运行环境的方方面面,诸如操作系统,Oracle自身,存储,网络等等几个大块.而操作系统则是Oracle稳定运行与最大化性能的基石.本文主要描述基于Linux系统下 Or ...

  4. ListBox

    <asp:ListBox runat="server" ID="txtName" Width ="200"  Height=" ...

  5. animate实例介绍

    1.animate,setInterval组合不断滚动: function Tscroll(){ $().animate(); } setInter(); //注意里面的是 Tscroll(),而不是 ...

  6. td:first-child 伪类 匹配第一个 匹配第一个 <td> 元素

    css代码: td:first-child{border-right: 1px solid #d9dbdd; } 备注:在下面的例子中,选择器匹配作为任何元素的第一个子元素的 p 元素: 链接:htt ...

  7. LeetCode —— Merge k Sorted Lists

    /* ** 算法的思路: ** 1.将k个链表的首元素进行建堆 ** 2.从堆中取出最小的元素,放到链表中 ** 3.如果取出元素的有后续的元素,则放入堆中,若没有则转步骤2,直到堆为空 */ #in ...

  8. Lua与C的交互

    Lua 与 C 的交互 Lua是一个嵌入式的语言,它不仅可以是一个独立运行的程序,也可以是一个用来嵌入其它应用的程序库. C API是一个C代码与Lua进行交互的函数集,它由以下几部分构成: 1.  ...

  9. 使用phpize增加php模块

    一,phpize的好处 什么时候我们要用phpize呢?我们在安装php时: ./configure --prefix=/apps/product/php --with-config-file-pat ...

  10. python 占位符 %s Format

    1.百分号方式 %[(name)][flags][width].[precision]typecode (name)      可选,用于选择指定的key flags          可选,可供选择 ...