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

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

  下面咱們就來一塊兒學習一下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容器也是可使用初始化列表,代碼以下:ide

//類使用初始化列表
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關鍵字便可自動推導類型明確的變量,例如:this

  

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

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

  

    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 請尊重別人的勞動成果,讓分享成爲一種美德,歡迎轉載。另外,文章在表述和代碼方面若有不妥之處,歡迎 批評指正。留下你的腳印,歡迎評論!

相關文章
相關標籤/搜索