2016年5月25日 星期三

0525 cocos2d-x static_cast dynamic_cast 差異

http://blog.csdn.net/star530/article/details/21990081

這篇博文其實和Cocos2dx 3.0關聯性並不大,只是我近來對強制類型轉換惡補了下,寫在這裡當筆記用吧...
抱著羞愧的心理,我決定本文儘量說的簡單、嚴肅點...
以前用C時,習慣用(int)a這樣的格式來強制轉換類型。用cocos2dx,例如下面這種寫法:
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. Sprite* sp = (Sprite*)this->getChildByTag(1);  
但畢竟cocos2dx是用C++而不是用C,所以我們應入鄉隨俗,還是應該用C++本家的方式來寫轉換格式會比較好。(其實我以前都是用C的寫法...)


為了完成強制類型轉換,C++中已經為我們提供了4中標準方法,它們是dynamic_cats, static_cast, const_cast, reinterpret_cast,用法形式如:dynamic_cast<類型說明符>(表達式),之所以分成4類,就表示他們各自有著不同的使用環境。


我覺的通常情況下用dynamic_cast最好,它檢查的更嚴格些,其次是static_cast,而後兩者也就是const_cast和reinterpret_cast較之前兩者貌似不太常用(我會告訴你我根本就沒用過嗎...),而且也不推薦使用,const_cast在用於去除const的地方還是有所發揮的,reinterpret_cast在轉換時,不會在內存中進行補足比特位(例如int轉換到double,需要補足4字節),這往往是不安全的,而且代碼也是不可移植的。
所以我主要介紹的還是static_cast和dynamic_cast。

1、static_cast
static_cast類似C風格的強制類型轉換。它適用於基類和子類之間轉換:其中子類指針轉換成父類指針是安全的;但父類指針轉換成子類指針是不安全的。用法如下:
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. class A { ... };  
  2. class B { ... };  
  3. class D : public B { ... };  
  4. void f(B* pb, D* pd)  
  5. {  
  6.     D* pd2 = static_cast<D*>(pb);        // 不安全, pb可能只是B的指針  
  7.     B* pb2 = static_cast<B*>(pd);        // 安全的  
  8.     A* pa2 = static_cast<A*>(pb);        //錯誤A與B沒有繼承關係  
  9. }  
在cocos2dx 中,有這樣的一種用法:
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. auto boy =  Sprite::create("boy.png");//創建一個精靈  
  2. boy->setPosition(Point(200,400));  
  3. boy->setTag(99);//設置精靈的tag  
  4. this->addChild(boy,2);  
  5.   
  6. //在其他函數裡,我們要使用到精靈boy,用下面的方法調用  
  7. auto boy = static_cast<Sprite*>(this->getChildByTag(99));  
  8. boy->setPosition(Point(50,50));//運行後精靈boy的坐標發生改變,說明獲取成功  
上面的情況是我在知道tag為99的child是一個Sprite類,所以我才會將其取出來後強制轉化為Sprite*,可是如果我只知道有個tag為99的東東,但不知道到底是什麼類型的,那會怎麼做呢?步驟其實很簡單:
1、取出一個骰子;
2、使出吃奶的力氣搖骰子;
3、根據點數的大小決定該轉換成什麼類型...................

這裡假設要轉換成LabelTTF類型的(很明顯猜錯了,應該是Sprite型的)
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. auto label = static_cast<LabelTTF*>(this->getChildByTag(99));  
  2. label->setString("天才一般的我肯定猜對了,哇哈哈,動感超人!");//呵呵,呵呵  
上面這種做法會產生什麼後果呢?呵呵。
其實我只是想通過這種方法告訴小夥伴們,珍愛生命,遠離賭博
那麼,有什麼辦法可以避免上述這種不靠譜的強制類型轉換嗎?回答當然是有的,那就是比安全那啥還安全的dynamic_cast
2、dynamic_cast
與其他強制類型轉換不同,dynamic_cast在轉換過程中涉及類型檢查。如果綁定到引用或指針的對象不是目標類型的對象,則dynamic_cast失敗,並返回nullptr。
換句話說:如果你要將Sprite* 強制轉化為LabelTTF,dynamic_cast絕對不允許你這麼亂搞的!它會用返回nullptr的形式告訴你,LabelTTF和Sprite並不是同一物種,重口味者慎入!
下面修改之前的代碼:
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. auto label = dynamic_cast<LabelTTF*>(this->getChildByTag(99));  
  2. if( label )  
  3. {  
  4.     label->setString("有了dynamic_cast,老闆再也不用擔心我亂來了");  
  5. }  
  6. else  
  7. {  
  8.     CCLOG("Attention : label doesn't point to LabelTTF Objective");    
  9. }  

沒有留言:

張貼留言

cocos2dx-lua 建立滑鼠監聽

重要關鍵字  EVENT_MOUSE_SCROLL addEventListenerWithSceneGraphPriority      if IsPc() then --建立滑鼠監聽         local listener = cc.EventListenerMouse...