• 从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 ");
    }
     
    // 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 ");
        return bRet;
    }
     
    // destruction
    CCar::~CCar()
    {
        if (m_pEngine)
        {
            delete m_pEngine;
            m_pEngine = NULL;
        }
     
        printf("CCar destructor ");
    }
     
    // 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。 祝编程愉快!

  • 相关阅读:
    分享jstl实现分页,类似百度分页
    分享git的常用命令
    ubuntu certbot 生成免费泛域名证书
    es创建普通索引以及各种查询
    动态代理
    开闭原则
    单一原则
    单例模式
    设计模式之观察者模式
    SpringBoot集成spring-data-jpa注入Bean失败
  • 原文地址:https://www.cnblogs.com/hackerl/p/4116038.html
Copyright © 2020-2023  润新知