从Objective-C转战C++ Android平台开发实践(C++/Java)

是否使用虚拟方法

  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。 祝编程愉快!

时间: 2024-11-02 02:20:26

从Objective-C转战C++ Android平台开发实践(C++/Java)的相关文章

为 Android 平台开发一个输入法

学习目标: 实现新的输入法 学习目的: 掌握Android输入法框架 学习收获: Android 1.5 新特色之一就是输入法框架(Input Method Framework,IMF),正是它的出现,才为诞生不带实体键盘的设备提供了可能.IMF设计用来支持不同的IME,包括了soft keyboard,hand-writing recognizes和hard keyboard translators.这里,我们把焦点锁定在soft keyboard上. 新特色对普通应用开发者而言,应该确保让应

<2014 05 10> Android平台开发攻略

1.标准SDK开发: IDE: Eclipse Netbeans Language: Java 2.标准NDK+SDK开发: IDE: Eclipse Language: Java(JNI) C/C++ 3.Tranditional linux开发 IDE: c4droid,   command line.vim,emacs Language: C/C++ ------------------------------------------------------------ In a mini

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

我和我的朋友参加一个比赛——物联网应用技能大赛,这个大赛所要求的技能有,硬件技术,Android平台开发技术,.NET平台开发技术,所以这是一个团队合作的比赛,基本上没有人能同时掌握这三种技术(在校生). 今天的一个任务是:串口通讯实验.面向Android平台开发,要求把Android工程部署到测试机上,然后打开串口为COM1,COM2,COM3及相应波特率的串口. 我们碰到的问题是,Android工程部署上之后,弹出“强制关闭”的消息框. 以下是我对”强制关闭“的理解: Android程序,弹

基于Android平台开发的手电筒Light

基于Android平台开发的手电筒Light 1.     需求分析: 在现代社会中,手机的功能越来越完善,手电筒就是这些功能中必不可少的一种.当行走在漆黑的道路上,当你在黑暗狭小的地方寻找物品,当你在家中停电之时,如果你的手机拥有了手电筒的功能,那将为你带来莫大的方便.当然,它的用处不仅仅只是这样,有了这样一个方便携带的手电筒,在许多时候都是大有益处,因此,开发出了手电筒这一应用程序. 2.     开发环境: 1. JDK Ver: jdk-7u4-windows-x64.exe 2. My

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

Android开发是当前最火的话题之一,但很少有人讨论这个领域的安全问题.本系列将分两期,探讨Android开发中常见的安全隐患和解决方案.第一期将从数据存储.网络通信.密码和认证策略这三个角度,带你走上Android软件安全开发实践之旅. 过去两年,研究人员已发现Android上的流行软件普遍存在安全缺陷或安全漏洞.漏洞频发的原因可能有很多,例如以下几种. 与一切都是集中管理的iOS相比,Android提供了一种开放的环境,在获得了灵活性.可以满足各种定制需求的同时,也损失了部分安全性. 开发

《移动平台开发实践》第三周学习任务

目录 20189230杨静怡 2018-2019-2 <移动平台开发实践>第3周学习总结 学习<Java和Android开发学习指南(第二版)>第5.6.8.9章-- 教材学习中的问题和解决过程 代码调试中的问题和解决过程 [代码托管] statistics.sh脚本运行结果的截图 上周考试错题总结 学习进度条 参考资料 20189230杨静怡 2018-2019-2 <移动平台开发实践>第3周学习总结 学习<Java和Android开发学习指南(第二版)>

《移动平台开发实践》第7周学习总结

20189208 2018-2019-2 <移动平台开发实践>第7周学习总结 教材学习内容总结 需求: 用户需求:用户提出的. 产品需求:由用户需求提炼出的需求. 需求分析一般步骤: 挖掘真实需求:(更快的马车) 目标用户 使用场景 想要解决的问题 提出解决方案 筛选和验证方案 软件项目需求分析 收集需求 分析需求:表层需求→深层需求→底层需求 需求评价 需求设计 验证需求 产品经理常用软件 Axure RP 墨刀 石墨文档 第27章主要介绍了5种控件布局方法: LinearLayOut-水平

20189208《移动平台开发实践》第10周学习总结

<移动平台开发实践>第10周学习总结 教材学习内容总结 第39章偏好 调用SharedPreference接口管理键/值对类型的应用程序设计,通过getDefaultSharePreferences静态方法传入 Context来获取SharedPreferences的默认实例.使用Android Preference API创建编辑设置的界面 第40章 第41章 第42章 教材学习中的问题和解决过程 问题1: 问题1解决方案: 问题2: 问题2解决方案: 代码调试中的问题和解决过程 问题1:

Android开发实践:Java层与Jni层的数组传递

Android开发中,经常会在Java代码与Jni层之间传递数组(byte[]),一个典型的应用是Java层把需要发送给客户端的数据流传递到Jni层,由Jni层的Socket代码发送出去,当然,Jni层也需要把从Socket接收到的数据流返回给Java层.我简单地总结了一下,从Java层到Jni层,从Jni层到JAVA层,各有3种传递方式,下面用代码示例简单地介绍一下. 示例代码的主要文件有两个,一个是Native.java,是Java层的类:另一个是Native.c,是JNI层的文件,关键的地