【Cocos2d-x游戲開發】細數Cocos2d-x開發中那些常用的C++11知識


  自從Cocos2d-x3.0開始,Cocos2dx就正式的使用了C++11標准.C++11簡潔方便的特性使程序的可拓展性和可維護性大大提高,也提高了代碼的書寫速度。

  下面我們就來一起學習一下Cocos2d-x開發中那些不得不了解的C++11知識。

 1.初始化列表

  POD結構或者數組根據成員在結構內定義的順序,可以使用初始化列表來進行初始化以簡化代碼。

   

struct StructA{
    int a;
    int b;
};

StructA sa={1,2};

  在C++03中,非POD結構的類或者STL容器並不支持這種簡便的寫法,而C++11提供了強大的支持。使用std::initializer_list可以讓類和普通函數使用初始化列表,並且STL容器也是可以使用初始化列表,代碼如下:

//類使用初始化列表
class ClassA{
public:
    ClassA(std::initializer_list<int>list){}
};

ClassA a = { 1, 2, 3 };

/*注意!使用std::initializer_list需要先include <initializer_list>頭文件*/
//函數使用初始化列表
void func(std::initializer_list<float>list){
    /*Function Body*/
}

func({1.6f,2.8f});
/*注意!使用std::initializer_list需要先include <initializer_list>頭文件*/
//STL標准容器使用初始化列表
vector<string> s = {"hello","C++","11"};

  可以看到在引入了std::initializer_list特性之后,初始化變量的工作簡潔了許多,非常方便。

 2.自動類型推導

  類型推導可以在編譯的時候自動來識別對象的類型,從而簡化代碼,更好的使用模版編程,使用auto關鍵字即可自動推導類型明確的變量,例如:

  

    /*自動類型推導*/
    vector<int> v;
    vector<int>::iterator it=v.begin();        //使用類型推導前
    auto it2 = v.begin();                    //使用類型推導后

  decltype也可以根據已有的對象自動識別類型,但是它和auto的不同之處是:auto是自動推導出表達式右邊的類型,而decltype是自動推導出任意一個變量的類型,並且可以用該類型來定義變量,說起來比較難理解,看下面的代碼就一目了然了:

  

    int num;
    decltype(num) b = 5;

 3.自動范圍推導

  在C++11以前,寫一個循環語句通常是這樣的:

  

    for (int i = 0; i < 10; i++){            //使用自動范圍推導前
        cout << i << endl;
    }

  而在C++11中,for語句新增了范圍迭代的寫法,該寫法可以簡化for循環的代碼,“:”符號左邊是要編歷的元素類型,可以是引用或者const引用類型;而“:”右邊是要編歷的容器可以是數組或者STL容器等,代碼如下:

  

    int arr []= { 1, 2, 3, 4, 5 };      //使用自動范圍推導后
    for (int &i : arr){
        cout << i << endl;
    }

  4.智能指針和空指針

  智能指針是一個類而並非是普通的指針,shared_ptr是一引用計數指針,一個shared_ptr只有在已經沒有任何其他shared_ptr指向其原本所指向的對象時,才會銷毀該對象。

  除了shared_ptr之外,還有weak_ptr,但是weak_ptr並不擁有其所指向的對象,因此不影響該對象的銷毀與否,也不能對weak_ptr解引用,只能判斷該指針是否已經被銷毀。下面舉個例子說明一下shared_ptr:

  

    /*智能指針和空指針*/
    //智能指針只能被智能指針賦值,不能用shared_ptr<int> pq= new int;
    shared_ptr<int> p1(new int);
    //用{ }進入一個新的作用域
    {
        //新的智能指針指向p1,這是相當於對int內存塊的一次retain
        shared_ptr<int> p2 = p1;
        *p2 = 123;
        //p2被銷毀,相當於對int內存塊的一次release,但是由於p1還指向該內存,引用計數器不為0,因此不會釋放
    }

    return 0;
    //p1也被銷毀,此時引用計數為0,int所占用的內存被自動回收

    /*注意!使用shared_ptr需要include <memory>*/

  如果將share_ptr定義為類的成員變量,那么此智能指針的retain引用會在該對象被釋放的時候才釋放。

  空指針nullptr的存在是為了解決NULL的二義性問題,因為NULL也可以代表0,nullptr的類型為nullptr_t,能隱式轉換為任何指針或者是成員指針的類型,也能和它們進行相等或者不等的比較。而nullptr不能隱式轉換為整數,也不能和整數做比較。

  

    void foo(char *);
    void foo(int);
    foo(NULL);        //調用的是void foo(int);
    foo(nullptr);    void foo(char *);

5.Lambda特性

  lambda表達式是一個非常好的新特性,當你需要在程序中添加一個新的臨時函數時,直接使用Lambda函數,會讓你感覺到原來寫程序還可以這么爽~(類似於Java中的 匿名內部類)。lambda的寫法如下:

  

[函數外部對象參數] (函數參數) -> 返回值類型{ 函數體}

  (1)[ ]中的函數外部對象參數,允許在函數體內直接調用函數外部的參數;

  (2)( )中的參數,同正常函數的參數沒有什么差異,是每次函數調用時傳入的變量;

  (3)->后面跟着函數返回值的類型;

  (4){ }里面可以編寫邏輯函數,並使用[ ]和( )傳入的參數

  定義在lambda函數相同作用域的參數引用也可以被使用,這種參數集合一般被稱為閉包,[ ]中可以填寫下面的幾種類型的參數,將定義lambda函數作用域內的變量傳入函數體中。

  1.[ ]可以沒有任何參數,這種情況下不傳入外部參數

  2.[a,&b]傳入變量a的值以及變量b的引用

  3.[&]以引用的方式傳入所有的變量

  4.[=]以傳值的方式傳入所有的變量,值不可以被修改

  5.[&,a]除了a用傳值的方式,其他變量都已引用的方式傳入

  6.[=,&a]除了a用引用的方式傳入,其他變量都以傳值的方式傳入

  下面讓我們通過一個例子來了解一下,當在lambda中使用了“=”傳入的參數,且對引用參數或者外部參數進行賦值操作之后,會產生意想不到的結果,並且還需注意在使用“&”時需要注意引用對象的生命周期。

  

    /*Lambda表達式*/
    int b, c, d;
    auto func0 = [&]()->void {b = 1; c = 2; d = 3; };
    auto func1 = [=]()->int {return 2 * 3; };
    auto func2 = [=, &b, &c]()->void {++b; c += d + b; };
    auto func3 = [=]()->int {return b + d; };

    func0();    //b,c,d分別為1,2,3
    c=func1();    //c=6
    func2();    //b=2;c=858993456,d=6;
    b = func3();//b=1717986916
    return 0;

  當Lambda被定義在類的成員函數中時,Lambda可以調用該類的private函數;當Lambda調用該類的成員函數時,操作成員變量或者其他成員函數時,需要將this傳入,=和&會傳入this。

  使用std::function可以存儲Lambda函數,比如可以用function<void()>來存儲func0,用function<int()>來存儲func1,帶有參數的函數可以直接在()內輸入參數類型,在使用function時要包含頭文件functional。

  

    #include <functional>
    function<void()> f1 = func0;
    function<int()>f2 = func1;    

  function還可以用於存放普通函數,靜態函數和類的公有成員函數,前兩者和lambda的用法一樣,直接將函數名賦值給function對象即可(無法識別重載的函數),但類的成員函數需要使用bind來綁定:

  

    ClassA *obj = new ClassA();
    function<void(int)> f2 = bind(&ClassA::memberFunc1,obj,std::placeholders::_1);
    function<void(int, char)>f3 = bind(&ClassA::memberFunc2,obj,std::placeholders::_2);

  使用bind函數綁定成員函數和對象指針,使用std::placeholders占位符來表示函數的參數數量,其后綴依次從1~N。

6.顯式虛函數重載

  override可以確保在重寫父類的虛函數,調整父類的虛函數時(改名字或者參數),不會忘記調整子類的虛函數。在編譯時,編譯器會為標記為override的虛函數檢查其父類是否有該虛函數:

class B{
public:
    virtual void virtuaalFunc(int);
};

class C{
public:
    virtual void virtuaalFunc(int) override;    //顯示重寫父類虛函數
    virtual void virtuaalFunc(char) override;    //錯誤
};

  final可以保證子類不能重寫函數,不能具有相同簽名的函數,或者類不能被繼承。(類似於Java中final用法)override和final並不是C++11的關鍵字,只是在特定的位置才有特殊的含義,在其他地方仍然是當作變量來用的。

 


作者:馬三小伙兒
出處:http://www.cnblogs.com/msxh/p/5869992.html 
請尊重別人的勞動成果,讓分享成為一種美德,歡迎轉載。另外,文章在表述和代碼方面如有不妥之處,歡迎
批評指正。留下你的腳印,歡迎評論!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM