C++ 11新特性在Cocos2dx 3.0应用

来源:互联网 发布:mcmc算法 编辑:程序博客网 时间:2024/04/28 11:56
 

      □文/传智播客C/C++高级讲师 童泽宇
  
  个人简介:曾就职于知名杀毒软件公司,长期从事计算机病毒研究,参与反病毒引擎、病毒鉴定器开发,熟悉CPU虚拟化技术,专注于操作系统底层,精通x86/x64平台逆向、C/C++,对Flame、sality、Conficker等知名病毒进行全面过分析,曾参与国安局相关项目的逆向分析,另外对Android系统的架构设计和实现原理有非常深入的理解和认识。童老师擅长将高深的知识通俗化,负责的理论简单化,热爱技术、热爱分享,在教学中将会把掌握最扎实最深入的技术积累献给每一位学员。

  大家都应该知道,Cocos2dx在2.x的版本和1.x的版本一直延续着Objective-C的设计模式,这让很多C++程序员感觉很不适应。因为语法改的既不像OC也不像C++,所以在开发难度上来说还是比较大的,然而在这点对于OC的程序员来说,就有便宜可占了。因为1.x和2.x中都用到了OC的设计模式,这样他们上手起来是比较easy的。但3.0版本以后,cocos2dx的官方也感觉这样不是很好,所以3.0版本以后对cocos2dx引擎进行了一个重构工作,剔除了Objective-C的设计模式,增添了C++11的新特性。

  下面,一起跟随我的文章深入探讨下我们Cocos2dx 正式版中的C++11的新特性吧!

  特性1:lambda表达式

  Cocos2dx 3.0版本后加入了lambda表达式,或者说C++11终于引入了lambda表达式,那么,什么是lambda表达式呢?
  例如调用<algorithm>中的std::sort,ISO C++98的写法是要先写一个compare函数:
  1.   bool compare(int & a, int & b)  
  2.   {  
  3.       return a > b;   // 降序排序  
  4.   }  
复制代码
  然后,再这样调用:
  1.   sort(a, a+n, compare);
复制代码
  然而,用ISO C++11标准新增的Lambda表达式,可以这么写:
  1.   sort(a, a + n, [](int a, int b){return a > b;}); // 降序排序  
复制代码
  这样一来,代码是不是简洁多了呢?
  由于Lambda的类型是唯一的,不能通过类型名来显式声明对应的对象,但可以利用auto关键字和类型推导:
  1.   auto f = [](int a, int b){return a > b;});  
复制代码
  和其它语言的一个较明显的区别是Lambda和C++的类型系统结合使用,如:
  1.   auto f = [=](int a, int b){return a > x;}); //x被捕获复制  
  2.   int x = 0, y = 1;  
  3.   auto g = [&](int x){return ++y;}); //y被捕获引用,调用g后会修改y,需要注意y的生存期  
  4. bool(*fp)(int, int) = [](int a, int b){return a > b;}); //不捕获时才可转换为函数指针  
复制代码
  下面讲下在cocos2dx 3.0 应该如何使用lambda:
  我先创建一个menu ,如果不使用labmda,menu里item需再写一个回调函数,如下:
  1.   auto closeItem = MenuItemImage::create(  
  2.                                           "CloseNormal.png",  
  3.                                           "CloseSelected.png",  
  4.                                           CC_CALLBACK_1(HelloWorld::menuCloseCallback,this));  
  5.                                             
  6.   void HelloWorld::menuCloseCallback(Object* sender)  
  7.   {  
  8.       Director::getInstance()->end();  
  9.   }  
复制代码
  使用了lambda后,可以这么使用:
  1.   auto closeItem = MenuItemImage::create(  
  2.                                           "CloseNormal.png",  
  3.                                           "CloseSelected.png",  
  4.                                           [](Object* sender)  
  5.                       {  
  6.                           Director::getInstance()->end();//直接在这里添加按钮要调用的代码  
  7.                       });         
复制代码
  这种写法是不是简洁很多?当然了,也可以将回调的代码单独取出来,这种写法的好处是可以多处调用callEnd。如下:
  1.   auto callEnd = [](Object* sender)  
  2.   {  
  3.       Director::getInstance()->end();//直接在这里添加按钮要调用的代码   
  4.   };    
  5.   auto closeItem = MenuItemImage::create(  
  6.                                           "CloseNormal.png",  
  7.                                           "CloseSelected.png",  
  8.                       allEnd);      
复制代码
  默认情况下,即捕获字段为[] 时,lambda表达式是不能访问任何外部变量的,即表达式的函数体内无法访问当前作用域下的变量。
  如果要设定表达式能够访问外部变量,可以在[]内写入“&”或者“=”加上变量名,其中“&”表示按引用访问,“=”表示按值访问,变量之间用逗号分隔,比如[=factor, &total] 表示按值访问变量factor,而按引用访问total。
  用“&”引用来举个例子:假设点击按钮后,我要创建一个精灵。修改callEnd:
  1.   auto callEnd = [](Object* sender)
  2.   {  
  3.       auto sp = Sprite::create("Hello.png");  
  4.       sp->setPosition(Point(100,100));  
  5.       this->addChild(sp,10);//这里报错  
  6.   };   
复制代码
  上面这种写法是错误的,因为表达式无法访问当前作用于的变量。下面继续改代码:
  1.   auto callEnd = [&](Object* sender)  
  2.   {  
  3.       auto sp = Sprite::create("Hello.png");  
  4.       sp->setPosition(Point(100,100));  
  5.       this->addChild(sp,10);//perfect  
  6.   };   
复制代码
  这样就没问题了。
  上面的例子都只是简单的应用。在cocos2dx用到lambda 的地方还有很多,例如创建一个监听事件:
  1.   // Make sprite1 touchable  
  2.   auto sprite1 = Sprite::create();  
  3.   auto listener1 = EventListenerTouchOneByOne::create();  
  4.   listener1->setSwallowTouches(true);  
  5.     
  6.   listener1->onTouchBegan = [](Touch* touch, Event* event){  
  7.       auto target = static_cast<Sprite*>(event->getCurrentTarget());  
  8.       return false;  
  9.   };  
  10.     
  11.   listener1->onTouchMoved = [](Touch* touch, Event* event){  
  12.       auto target = static_cast<Sprite*>(event->getCurrentTarget());  
  13.       target->setPosition(target->getPosition() + touch->getDelta());  
  14.   };  
  15.     
  16.   listener1->onTouchEnded = [=](Touch* touch, Event* event){  
  17.       auto target = static_cast<Sprite*>(event->getCurrentTarget());  
  18.   };                    
  19.    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, sprite1);   
复制代码
  Ok,那么我们特性其一的lambda就介绍完了。

  特性2:auto关键字:

  C++11中引入auto第一种作用是为了自动类型推导。
  auto的自动类型推导,用于从初始化表达式中推断出变量的数据类型。通过auto的自动类型推导,可以大大简化我们的编程工作。
  auto实际上是在编译时对变量进行了类型推导,所以不会对程序的运行效率造成不良影响。
  另外,似乎auto并不会影响编译速度,因为编译时本来也要右侧推导然后判断与左侧是否匹配。
  cocos2dx 3.0使用了auto自动类型变量,这个是C++11的新标准,比如原来要指定变量是int还是float,现在可以用auto,在赋值的时候,编译器自动识别类型。
  那么我们来举个简单的例子看一下,auto在cocos2dx中的应用:
  现在是2.x的版本:
  1.   CCSprite *pSprite = CCSprite::create(“HelloWorld.png”);
复制代码
  3.0正式版以后:
  1. auto pSprite = Sprite::create(“HelloWorld.png”);
复制代码
  是不是感觉很简单了?

  好了C++11的新特性还有很多,我们在以后的日子中会陆续提到,好了,今天就到这里。


更多IT前沿、技术学习、面试技巧、IT笑话,微信搜索CZTEKAN,关注传智特刊,我为IT狂!或者点击进行邮件订阅图片,了解传智特刊的最新资讯。 
----------------------------------------------------------------------------------------------------
传智播客教育科技有限公司——专注于Java、.Net、PHP、网页平面UI、iOS、C/C++设计工程师的培训
       

0 0