cocos2d-x-SpriteFrameCache

| 分类 cocos2d-x  | 标签 cocos2d-x 源码学习 

本文为xiedantibu原创,转载请注明作者及出处!

###目录 —-     SpriteFrame
    SpriteFrameCache
    SpriteFrameCache与TextureCache
    plist文件格式
    COCOS2D-X常用宏
    C相关方法学习


####SpriteFrame-精灵帧

SpriteFrame我们查看下其源码,发现其持有一个Texture2D *_texture以及相关的纹理Name,以及纹理偏移量等。那SpriteFrame的主要作用其实也就是为了保存从plist文件中读取的纹理信息,配合SpriteFrameCache实现精灵帧缓存的作用。下面是SpriteFrame的相关源码:

构造SpriteFrame

  1. static SpriteFrame* create(const std::string& filename, const Rect& rect);
  2. static SpriteFrame* create(const std::string& filename, const Rect& rect, bool rotated, const Vec2& offset, const Size& originalSize);//很少用
  3. static SpriteFrame* createWithTexture(Texture2D* pobTexture, const Rect& rect);//通过纹理Texture2D以及Rect创建精灵帧
  4. static SpriteFrame* createWithTexture(Texture2D* pobTexture, const Rect& rect, bool rotated, const Vec2& offset, const Size& originalSize);

以下为初始化精灵帧的主要方法

  1. bool initWithTexture(Texture2D* pobTexture, const Rect& rect);
  2. bool initWithTextureFilename(const std::string& filename, const Rect& rect);
  3. bool initWithTexture(Texture2D* pobTexture, const Rect& rect, bool rotated, const Vec2& offset, const Size& originalSize)

通过精灵帧获取设置纹理

  1. Texture2D* getTexture(void);
  2. void setTexture(Texture2D* pobTexture); 相关属性
  3. Vec2 _offset;//偏移量
  4. Size _originalSize;原始大小
  5. Rect _rectInPixels;//像素RECT
  6. bool _rotated;//是否旋转
  7. Rect _rect;
  8. Vec2 _offsetInPixels;//像素单位偏移量
  9. Size _originalSizeInPixels;
  10. Texture2D *_texture;//持有的纹理指针
  11. std::string _textureFilename;//纹理名字 --- <a id='SpriteFrameCache' name='SpriteFrameCache'> </a> ####[SpriteFrameCache](#top). ---

SpriteFrameCache也就是精灵帧缓存,其主要的工作流程是读取一张大的纹理图片,同时通过plist文件,将这张大图片上的小图片的相关信息,也就是截取小图片的纹理信息保存在精灵帧中。

  1. Map<std::string, SpriteFrame*> _spriteFrames;//保存精灵帧的啊
  2. ValueMap _spriteFramesAliases;//format值为3, Zwoptex导出的格式,在format为3的情况下,保存key为aliases的精灵帧,在format其他情况下没有赋值该值
  3. std::set<std::string>* _loadedFileNames;//大图片的名字,也就是plist的名字

获取单例的SpriteFrameCache对象。sharedSpriteFrameCache方法已经弃用

  1. static SpriteFrameCache* getInstance(void);

销毁SpriteFrameCache对象,purgeSharedSpriteFrameCache已经弃用

  1. void SpriteFrameCache::destroyInstance()
  2. {
  3. CC_SAFE_RELEASE_NULL(_sharedSpriteFrameCache);
  4. }

初始化_spriteFrames等属性,在getInstance中回调init方法

  1. bool SpriteFrameCache::init(void)
  2. {
  3. _spriteFrames.reserve(20);//设置所需要保存的帧的数量,默认数量为20
  4. _spriteFramesAliases.reserve(20);//设置所需要保存aliases的精灵帧的数量,默认为20
  5. _loadedFileNames = new std::set<std::string>();
  6. return true;
  7. }

_spriteFrames是cocos2d::Map<K,V>类型,cocos2d::Map<K,V>是使用std::unordered_map作为底层结构的关联式容器。而std::unordered_map是一个存储键值对的关联式容器,它可以通过它们的键快速检索对应的值。使用unordered_map,键通常是唯一的,而值则与这个键对应。

在unordered_map内部,元素是无序,它们是根据键的哈希值来存取的,存取的时间复杂度是常量,超级快。(参考自:http://www.cocoachina.com/bbs/read.php?tid=202255)

将精灵帧添加到_spriteFrames中

  1. void addSpriteFramesWithFile(const std::string& plist);//自动创建的纹理Texture2D
  2. void addSpriteFramesWithFile(const std::string& plist, const std::string& textureFileName);//需要传入纹理名字,通过名字创建纹理
  3. void addSpriteFramesWithFile(const std::string&plist, Texture2D *texture);//直接传入一个纹理 以上三个方法其中2,3方法类似,都是直接创建Texture2D,调用addSpriteFramesWithDictionary方法,关于方法1,则需要遍历plist文件,获取纹理名字,来创建纹理。下面就来看看第一个方法的具体实现:
  4. void SpriteFrameCache::addSpriteFramesWithFile(const std::string& pszPlist)
  5. {
  6. if (_loadedFileNames->find(pszPlist) == _loadedFileNames->end())//通过查找_loadedFileNames来判断是否该plist已经将精灵帧添加到精灵帧缓存中
  7. {
  8. std::string fullPath = FileUtils::getInstance()->fullPathForFilename(pszPlist);//获取该plist的完整路径
  9. ValueMap dict = FileUtils::getInstance()->getValueMapFromFile(fullPath);//将该plist文件转换成ValueMap
  10. string texturePath("");//初始化纹理名字路径
  11. if (dict.find("metadata") != dict.end())//在dict中查找是否含有metadata的key
  12. {
  13. ValueMap& metadataDict = dict["metadata"].asValueMap();//将metadata的value转换成ValueMap类型
  14. texturePath = metadataDict["textureFileName"].asString();//查找metadataDict中是否含有textureFileName这个key,如果有把她的value转换成string类型
  15. }
  16. if (!texturePath.empty())//判断路径是否为空
  17. {
  18. texturePath = FileUtils::getInstance()->fullPathFromRelativeFile(texturePath.c_str(), pszPlist);//获取纹理其完整路径
  19. }
  20. else
  21. {
  22. texturePath = pszPlist;//如果路径为空,则直接把plist的路径赋值给他
  23. size_t startPos = texturePath.find_last_of("."); //找到其后缀名.的位置
  24. texturePath = texturePath.erase(startPos);//抹除.后面的全部内容
  25. texturePath = texturePath.append(".png");//添加上.png,这里要看清是png类型,所以如果没有加密的plist文件,需要确保纹理图片是png,且名字要一样
  26. }
  27. Texture2D *texture = Director::getInstance()->getTextureCache()->addImage(texturePath.c_str());//终于找到这一步,和方法2,3一样,将纹理图片名字传给纹理缓存,创建纹理
  28. if (texture)
  29. {
  30. addSpriteFramesWithDictionary(dict, texture);//这方法是干货,将plist的内容,以及纹理Texture2D传过去,为啥要Texture2D呢?因为精灵帧需要啊.真正的处理plist文件,保存精灵帧的地方
  31. _loadedFileNames->insert(pszPlist);//将该纹理名字插入_loadedFileNames中,方便前面的判断
  32. }
  33. else
  34. {
  35. CCLOG("cocos2d: SpriteFrameCache: Couldn't load texture");
  36. }
  37. }
  38. }

在上面我们看到addSpriteFramesWithFile三个方法都调用了addSpriteFramesWithDictionary这方法,可见他的重要性,在看这代码之前我们得先了解下plist文件,看完了也得看代码了:

  1. void SpriteFrameCache::addSpriteFramesWithDictionary(ValueMap& dictionary, Texture2D* texture)
  2. {
  3. //typedef std::unordered_map<std::string, Value> ValueMap
  4. ValueMap& framesDict = dictionary["frames"].asValueMap();//获取key为frames的values
  5. int format = 0;//plist的格式类型
  6. if (dictionary.find("metadata") != dictionary.end())//查找key为metadata
  7. {
  8. ValueMap& metadataDict = dictionary["metadata"].asValueMap();
  9. format = metadataDict["format"].asInt();//获取format的类型
  10. }
  11. for (auto iter = framesDict.begin(); iter != framesDict.end(); ++iter)//迭代framesDict
  12. {
  13. ValueMap& frameDict = iter->second.asValueMap();//获取value值
  14. std::string spriteFrameName = iter->first;//获取key值,也就是图片帧的名字
  15. SpriteFrame* spriteFrame = _spriteFrames.at(spriteFrameName);//查找在_spriteFrames是否有记录相同名字的图片
  16. if (spriteFrame)//在_spriteFrames中已经含有spriteFrameName的帧,则调过继续
  17. {
  18. continue;
  19. }
  20. if(format == 0)
  21. {
  22. //格式为0,Flash版本的具体逻辑省虑。。
  23. }
  24. else if(format == 1 || format == 2) //TexturePacker的主要文件格式
  25. {
  26. Rect frame = RectFromString(frameDict["frame"].asString());//将String类型转换成Rect类型
  27. bool rotated = false;
  28. if (format == 2)
  29. {
  30. rotated = frameDict["rotated"].asBool();
  31. }
  32. Vec2 offset = PointFromString(frameDict["offset"].asString());//将String类型转换成Vec2
  33. Size sourceSize = SizeFromString(frameDict["sourceSize"].asString());//将string类型转换成Size
  34. spriteFrame = new SpriteFrame();//创建一个精灵帧
  35. spriteFrame->initWithTexture(texture,
  36. frame,
  37. rotated,
  38. offset,
  39. sourceSize
  40. );//初始化一个精灵帧,将一系列参数传入
  41. }
  42. else if (format == 3)//Zwoptes1.0.2以后的主要文件格式
  43. {
  44. Size spriteSize = SizeFromString(frameDict["spriteSize"].asString());
  45. Vec2 spriteOffset = PointFromString(frameDict["spriteOffset"].asString());
  46. Size spriteSourceSize = SizeFromString(frameDict["spriteSourceSize"].asString());
  47. Rect textureRect = RectFromString(frameDict["textureRect"].asString());
  48. bool textureRotated = frameDict["textureRotated"].asBool();
  49. ValueVector& aliases = frameDict["aliases"].asValueVector();//获取aliases的值,返回的是一个数组,具体查看下文plist-3文档
  50. for(const auto &value : aliases) {
  51. std::string oneAlias = value.asString();
  52. if (_spriteFramesAliases.find(oneAlias) != _spriteFramesAliases.end())
  53. {
  54. }
  55. _spriteFramesAliases[oneAlias] = Value(spriteFrameName);//将key为oneAlias,value为Value(spriteFrameName)赋值到_spriteFramesAliases
  56. }
  57. spriteFrame = new SpriteFrame();
  58. spriteFrame->initWithTexture(texture,
  59. Rect(textureRect.origin.x, textureRect.origin.y, spriteSize.width, spriteSize.height),
  60. textureRotated,
  61. spriteOffset,
  62. spriteSourceSize);
  63. }
  64. // add sprite frame
  65. _spriteFrames.insert(spriteFrameName, spriteFrame);//将图片纹理名字,已经精灵帧插入到_spriteFrames中
  66. spriteFrame->release();
  67. }

除了通过plist文件插入精灵帧外,还可以直接将精灵帧插入

  1. void addSpriteFrame(SpriteFrame *frame, const std::string& frameName);//通过传入精灵帧,以及纹理名字。如果在_spriteFrames已经传在frameName的精灵帧,那原先的精灵帧将被覆盖

有添加插入精灵帧,当然也就有移除精灵帧,我们在插入的过程中其实我们知道,精灵帧主要是插入到_spriteFrames,移除当然也就是移除_spriteFrames里的东西,当然在此过程中也就需要移除_loadedFileNames。否则我下次通过plist插入不进来精灵帧啊,当然在次过程中不能忘了_spriteFramesAliases,这仅仅只在format == 3的时候保存了纹理name.下面大体的看下移除的方法:

  1. void removeSpriteFrames();//移除全部的精灵帧,只有把上诉三个属性全部clear就可以
  2. void removeUnusedSpriteFrames();//移除没有使用的精灵帧,什么叫没有用的精灵帧呢??SpriteFrame的引用计数为1,那就是没有使用啊。这样就可以通过_spriteFrames.erase(toRemoveFrames)移除没有使用的了。
  3. void removeSpriteFrameByName(const std::string& name);//根据名字移除,那直接下面两个方法不就可以_spriteFrames.erase(key)。_spriteFramesAliases.erase(key);具体的还是见代码好啊
  4. void removeSpriteFramesFromTexture(Texture2D* texture);//通过迭代比较精灵帧的纹理是否和texture相等,来移除对应的纹理精灵
  5. void removeSpriteFramesFromFile(const std::string& plist);//根据plist文件移除精灵,好好想下,移除的步骤其实,就是得知道纹理图片的名字,所以肯定是得通过ValueMap把plist的纹理图片找出来,移除图片,所以当前方法会用到下面的方法
  6. void removeSpriteFramesFromDictionary(ValueMap& dictionary);//这方法也就是在上面方法将的,通过ValueMap把图片名字取出来,移除啊

移除精灵帧主要通过两种途径,要不就是根据纹理名字erase。要不就是通过比较精灵帧中的纹理是否和我将要移除的纹理一样来erase。
根据名字从精灵帧缓冲中获取精灵帧,当然也就很轻松了啊。。。

  1. SpriteFrame* getSpriteFrameByName(const std::string& name);

####SpriteFrameCache vs. TextureCache — 以下摘抄自:http://www.cocoachina.com/bbs/read.php?tid=200359
SpriteFrameCache精灵框帧缓存。顾名思义,这里缓存的是精灵帧SpriteFrame,它主要服务于多张碎图合并出来的纹理图片。这种纹理在一张大图中包含了多张小图,直接通过TextureCache引用会有诸多不便,因而衍生出来精灵框帧的处理方式,即把截取好的纹理信息保存在一个精灵框帧内,精灵通过切换不同的框帧来显示出不同的图案。 跟TextureCache功能一样,将SpriteFrame缓存起来,在下次使用的时候直接去取。不过跟TextureCache不同的是,如果内存池中不存在要查找的图片,它会提示找不到,而不会去本地加载图片。

  1. * TextureCache时最底层也是最有效的纹理缓存,缓存的是加载到内存中的纹理资源,也就是图片资源。
  2. * SpriteFrameCache精灵框帧缓存,缓存的时精灵帧。
  3. * SpriteFrameCache是基于TextureCache上的封装。缓存的是精灵帧,是纹理指定区域的矩形块。各精灵帧都在同一纹理中,通过切换不同的框帧来显示出不同的图案。

####plist文件格式 — 以下摘抄自:http://zengrong.net/post/1981.htm

  1. 什么是plist文件格式?

    1. 这是一种人类可读的串行化对象文件,由苹果公司发明,最早用于NeXTSTEP系统。详情看这里:Plist(http://zh.wikipedia.org/wiki/Plist) 。cocos2d-x 从 cocos2d-iphone 发展而来,因此在引擎中大量使用了这种文件格式。
  2. cocos2d-x在哪些地方使用了plist格式?

    1. *.图像纹理定义文件:将多个纹理拼在一张大图上,使用 CCSpriteFrameCache 可以载入这类plist文件;
    2. *.Label纹理定义文件:作用与图像纹理定义文件类似,只不过处理的是自己,面向 CCLabelAtlas
    3. *.帧动画定义:定义一个或多个动画中,使用哪些纹理,使用 CCAnimationCache 可以载入这类plist文件;
  3. 图像纹理定义文件格式说明

    1. cocos2d-x中的纹理定义格式,是以Zwoptex生成的格式为标准的。
    2. Zwoptex生成的格式,有4种主要不同的版本:
    3. *.format值为0,代表Flash版本;
    4. *.format值为1Zwoptex 0.4b以前支持;
    5. *.format值为2Zwoptex 1.0以后支持,与format1的区别在于支持旋转;
    6. *.format值为3,属性名称进行了大幅修改,Zwoptes1.0.2之后支持。
    7. 3种格式的plist文件,cocos2d-x都能支持,具体的解析代码在CCSpriteFrameCache::addSpriteFramesWithDictionary
    8. TexturePacker生成的for cocos2d plist格式与Zwoptex生成的format2的格式相同。
  4. format为0的plist文件

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    3. <plist version="1.0">
    4. <dict>
    5. <key>texture</key>
    6. <dict>
    7. <key>width</key>
    8. <integer>256</integer>
    9. <key>height</key>
    10. <integer>128</integer>
    11. </dict>
    12. <key>frames</key>
    13. <dict>
    14. <key>grossini.png</key>
    15. <dict>
    16. <key>x</key>
    17. <integer>103</integer>
    18. <key>y</key>
    19. <integer>1</integer>
    20. <key>width</key>
    21. <integer>51</integer>
    22. <key>height</key>
    23. <integer>109</integer>
    24. <key>offsetX</key>
    25. <real>0</real>
    26. <key>offsetY</key>
    27. <real>-1</real>
    28. <key>originalWidth</key>
    29. <integer>85</integer>
    30. <key>originalHeight</key>
    31. <integer>121</integer>
    32. </dict>
    33. </dict>
    34. </dict>
    35. </plist>
  5. format为2的plist文件

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    3. <plist version="1.0">
    4. <dict>
    5. <key>frames</key>
    6. <dict>
    7. <key>parts-dragon_leg_l.png</key>
    8. <dict>
    9. <key>frame</key>
    10. <string>{ {866,2},{152,254} }</string>
    11. <key>offset</key>
    12. <string>{0,0}</string>
    13. <key>rotated</key>
    14. <false/>
    15. <key>sourceColorRect</key>
    16. <string>{ {0,0},{152,254} }</string>
    17. <key>sourceSize</key>
    18. <string>{152,254}</string>
    19. </dict>
    20. </dict>
    21. <key>metadata</key>
    22. <dict>
    23. <key>format</key>
    24. <integer>2</integer>
    25. <key>realTextureFileName</key>
    26. <string>dragon.png</string>
    27. <key>size</key>
    28. <string>{1024,2048}</string>
    29. <key>smartupdate</key>
    30. <string>$TexturePacker:SmartUpdate:26d1d28da42d49170ab3142654fea750:1/1$</string>
    31. <key>textureFileName</key>
    32. <string>dragon.png</string>
    33. </dict>
    34. </dict>
    35. </plist>
  6. format为3的plist文件

  1. <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  2. <plist version="1.0">
  3. <dict>
  4. <key>frames</key>
  5. <dict>
  6. <key>armyLevelBg.png</key>
  7. <dict>
  8. <key>aliases</key>
  9. <array/>
  10. <key>spriteColorRect</key>
  11. <string>{ {0, 0}, {61, 36} }</string>
  12. <key>spriteOffset</key>
  13. <string>{0, -0}</string>
  14. <key>spriteSize</key>
  15. <string>{61, 36}</string>
  16. <key>spriteSourceSize</key>
  17. <string>{61, 36}</string>
  18. <key>spriteTrimmed</key>
  19. <true/>
  20. <key>textureRect</key>
  21. <string>{ {195, 2}, {36, 61} }</string>
  22. <key>textureRotated</key>
  23. <true/>
  24. </dict>
  25. </dict>
  26. <key>metadata</key>
  27. <dict>
  28. <key>version</key>
  29. <string>1.6.0</string>
  30. <key>format</key>
  31. <integer>3</integer>
  32. <key>size</key>
  33. <string>{256, 512}</string>
  34. <key>name</key>
  35. <string>army_zw.zwd</string>
  36. <key>textureFileName</key>
  37. <string>army_zw_cocos2d.png</string>
  38. <key>premultipliedAlpha</key>
  39. <false/>
  40. </dict>
  41. </dict>
  42. </plist>

####COCOS2D-X常用宏.

  1. #define CC_SWAP(x, y)//交互x,y的值
  2. #define CCRANDOM_MINUS1_1()//生成一个 -1 到 1的随机数
  3. #define CCRANDOM_0_1() // 生成一个 0 到 1的随机数
  4. #define CC_DEGREES_TO_RADIANS(__ANGLE__) // 角度转弧度
  5. #define CC_RADIANS_TO_DEGREES(__ANGLE__) //弧度转角度
  6. #define kRepeatForever //定时器永远执行
  7. #define CC_BLEND_SRC //GL_ONE表示使用0.0作为因子,实际上相当于不使用这种颜色参与混合运算
  8. #define CC_BLEND_DST //GL_ONE_MINUS_SRC_ALPHA表示用1.0减去源颜色的alpha值来作为因子
  9. #define CC_NODE_DRAW_SETUP() //getGLProgram()->use(); getGLProgram()->setUniformsForBuiltins(_modelViewTransform);设置gl的状态,以及设置模型视图矩阵以及投影矩阵
  10. #define CC_DIRECTOR_END()/// 停止 director 并从内存中移除, 从父级移除 CCGLView
  11. #define FLT_EPSILON //趋0最小float
  12. #define DISALLOW_COPY_AND_ASSIGN(TypeName) //用来限制类型复制、拷贝和默认的一些转换操作等对class类型变量的误操作,也可以提高性能,减少编译器自作主张为我们生成一些无法预料的代码
  13. #define CC_CONTENT_SCALE_FACTOR()//缩放因子
  14. #define CC_RECT_PIXELS_TO_POINTS(__rect_in_pixels__) //RECT的转换,主要是除以CC_CONTENT_SCALE_FACTOR()
  15. #define CC_RECT_POINTS_TO_PIXELS(__rect_in_points_points__)//RECT的转换 主要通过*CC_CONTENT_SCALE_FACTOR()
  16. #define CC_POINT_PIXELS_TO_POINTS(__pixels__)//点的转换 主要是除以CC_CONTENT_SCALE_FACTOR()
  17. #define CC_POINT_POINTS_TO_PIXELS(__points__)//点的转换 主要通过*CC_CONTENT_SCALE_FACTOR()
  18. #define CC_SIZE_PIXELS_TO_POINTS(__size_in_pixels__)//SIZE的转换
  19. #define CC_SIZE_POINTS_TO_PIXELS(__size_in_points__)
  20. #define CHECK_GL_ERROR_DEBUG()//检测opengl的错误
  21. #define CC_INCREMENT_GL_DRAWS(__n__)//batches绘制次数
  22. #define CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(__drawcalls__, __vertices__)//batches绘制次数,以及vertices绘制个数
  23. /**
  24. 以下CC_CALLBACK_* 都是std::bind的宏定义,由于std::bind的占位符的数量不一样,也就形成了CC_CALLBACK_0,CC_CALLBACK_1等形式。
  25. __target__表示执行这个回调函数的具体对象;##__VA_ARGS__是可变参数宏,std::bind是在C++ 11里新加入的成员。可以将bind函数看作一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表。调用bind的一般形式为: auto newCallback = bind(callback,arg_list); 其中,newCallback是一个可调用对象,arg_list是可以用逗号分隔的参数列表,至于是啥参数,那就看callback函数里有啥参数啦。也就是说,当我们调用newCallback时,newCallback会调用函数callback,并传递参数arg_list给callback.
  26. 有一个函数callback,如:int callback(int one,char two,double three);
  27. 下面我们用bind来调用callback:
  28. auto newCallback = bind(callback,_1,_2,1.5);
  29. int x = newCallback(10,'h'); //这句相当于:int x = callback(10,'h',1.5);
  30. “_1″是一个占位符对象,用于表示当函数callback通过函数newCallback进行调用时,函数newCallback的第一个参数在函数callback的参数列表中的位置。第一个参数称为”_1″, 第二个参数为”_2″,依此类推,有意思吧。至于‘1.5’是指默认参数,它处于_1和_2的后面,所以它就是double类型的参数了.
  31. */
  32. #define CC_CALLBACK_0(__selector__,__target__, ...)//std::bind(&__selector__,__target__, ##__VA_ARGS__)
  33. #define CC_CALLBACK_1(__selector__,__target__, ...) //std::bind(&__selector__,__target__, std::placeholders::_1, ##__VA_ARGS__)
  34. #define CC_CALLBACK_2(__selector__,__target__, ...) //std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, ##__VA_ARGS__)
  35. #define CC_CALLBACK_3(__selector__,__target__, ...) //std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, ##__VA_ARGS__)

####C相关方法学习.

+. void *memcpy(void *dest, const void *src, size_t n):从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中.

+. strcpy和memcpy主要有以下3方面的区别:

  1. * 复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
  2. * 复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度
  3. * 用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy

+. erase函数的原型如下:

  1. * string& erase ( size_t pos = 0, size_t n = npos );
  2. * iterator erase ( iterator position );
  3. * iterator erase ( iterator first, iterator last );

+. 也就是说erase有三种用法:

  1. * erase(pos,n); 删除从pos开始的n个字符,比如erase(0,1)就是删除第一个字符
  2. * erase(position);删除position处的一个字符(position是个string类型的迭代器)
  3. * erase(first,last);删除从firstlast之间的字符(firstlast都是迭代器)

青春是一场大雨,即使感冒了,还盼回头再淋一次...image...微笑永远是一个人身上最好看的东西...


PREVIOUS     NEXT