因为偶然的机会,在图书馆看到《深入理解C++ 11:C++11新特性解析和应用》这本书,大致扫下,受益匪浅,就果断借出来,对于其中的部分内容进行详读并亲自编程测试相关代码,也就有了整理写出这篇读书笔记的基础。C++作为踏入编程的最初语言,一直充满感情,而C++11作为新标准虽然推出一段时间了,却因为总总原因直到现在才去开始真正了解,不过一句话回荡在脑中:当你认为为时已晚的时候,恰恰是最早的时候!从C++98到C++11, C++11标准经历了10几年的沉淀,以全新的姿态迎接新的挑战,长话短说,进入正题,来一起了解吧。(注:本笔记中所有代码在Code::Blocks下编辑,使用gcc-4.9.3 -std=c++11模式下编译)

C++11的新基础特性

1.1 用于兼容C99特性的宏,可以检查编译系统对标准C库的支持情况,不过测试部分显示未定义。

  1. cout<<"Standard Clib: "<< __STDC_HOSTED__<<endl; //Standard Clib: 1(指定编译器目标系统是否包含完整的C库)
  2. cout<<"Standard C: "<<__STDC__<<endl; //__STDC__:1(指定编译器目标系统是否与C标准一致)
  3. //cout<<"C Standard Version: "<<__STDC_VERSION__<<endl; //测试gcc 没有定义(支持标准C库的版本)
  4. //cout<< "ISO/IEC: "<<__STDC_ISO_10646__<<endl; //测试gcc 没有定义

  

1.2 __func__ 用于获得当前函数名字符串的宏

  1. const char * Stanard_Macros(void)
  2. {
  3. //......
  4. return __func__; //返回值:Stanard_Macros
  5. }

  

1.3 _Pragma 预处理操作符,与#pragma功能相同,不过因为支持传递字符串,所以可以用宏命令替代,如对于经常使用的头文件单次包含。

  1. //头文件防止重复包含
  2. #pragma once;
  3.  
  4. _Pragma("once");
  5.  
  6. #define PRAGMA(x) _Pragma(#x) //宏命令中使用#可以实现替换字符串化
  7. PRAGMA(once);

 

1.4 __VA_ARGS__ 变长参数的宏定义是指宏定义中参数列表的最后一个参数为..., 而实现部分可以用__VA_ARGS__替换

  1. //__FILE__当前文件路径
  2. //__LINE__当前文本行
  3. #define LOG(...){ \
  4. fprintf(stderr, "%s: Line %d:\t", __FILE__, __LINE__);\ //输出错误的文件及行号地址
  5. fprintf(stderr, __VA_ARGS__);\             //输出错误的数据
  6. fprintf(stderr, "\n"); \
  7. }
  8.  
  9. LOG("%s", "NO ERR!"); // xxxx:xxxx: NO ERR!

 

1.5 新的整型long long/unsigned long long(长度不小于64位)

  1. long long int lli = -90000000000LL;
  2. unsigned long long int ulli = 9000000000000ULL;
  3. cout<<"LLONG_MIN: "<<LLONG_MIN<<endl; //LLONG_MIN: -9223372036854775808
  4. cout<<"LLONG_MAX: "<<LLONG_MAX<<endl; //LLONG_MAX: 9223372036854775807
  5. cout<<"ULLONG_MAX: "<<ULLONG_MAX<<endl; //ULLONG_MAX: 18446744073709551615

  

1.6 断言帮助开发者快速定位问题违反程序前提条件的错误,不过断言只在程序运行时执行,这在某些情况下,是不可接受的,特别是对于模板实例化时出现的错误,应该在编译器就确定。在C++11中引入了static_assert断言来解决问题,它支持两个参数输入,一个是返回bool型的表达式,另一个是警告信息。

  1. static_assert(sizeof(b)==sizeof(a), "the parameters of bit_copy must have same width"); //静态断言,编译器确定,返回false则触发告警信息

  

1.7 noexcept修饰符和noexcept操纵符是提供给库作者使用,表示函数如果出现异常,不会抛出,编译器会直接调用std::terminate()函数来终止程序运行,从而阻止了异常的的传播和扩散。此外:C++11中类析构函数默认是noexcept(true),不过注意noexcept只会阻止异常的传播和扩散(这对于定位错误很有帮助),而不会阻止异常(如throw语句产生异常的)的发生。

  1. const char * Stanard_Macros(void) noexcept     //相当于noexcept(true), 如果有异常会发生,不会传播和扩散,编译会调用std::terminate()来终止程序运行
  2.  
  3. const char * Stanard_Macros(void) noexcept(false) //noexcept中可以为结果为bool型的表达式

  

1.8 类成员变量的快速初始化和新的列表初始化,在C++11中,除了静态变量,对于其它变量也允许使用等号或{}进行就地初始化。

  1. class Mem{
  2. public:
  3. Mem(int i): m(i){};
  4. ~Mem(){};
  5. const char *ShowMem(void){ std::cout<<"Mem: "<<m<<" ";
  6. return __func__;
  7. };
  8. private:
  9. int m{};
  10. };
  11.  
  12. //快速初始化
  13. //初始化列表优于就地的列表初始化
  14. class Init{
  15. public:
  16. Init(): a(){}; Init(int d): val('G'), a(d){}; //初始化列表实际效果后作用,效果上优于列表初始化
  17. // ~Init(){ throw 1; };
  18. ~Init(){};
  19. const char * showPara(std::string str);
  20. int a;
  21. private:
  22. char val{'g'};       //成员变量的快速初始化
  23. Mem mem{};
  24. std::string name{"Init"};
  25. };
  26.  
  27. //C++的成员变量快速初始化
  28. Init init1{}; //C++11的统一列表初始化
  29. Init init2;
  30. init1.showPara("init1: "); //init1: 5 init1: G name :Init Mem: 1 mem :ShowMem
  31. init2.showPara("init2: "); //init2: 0 init2: g name :Init Mem: 1 mem :ShowMem

  

1.9 非静态成员的sizeof, sizeof作为运算符,对于处理数组,类和对象时经常用到,不过在之前的C++98中,对于非静态成员是不能直接编译的,需要借用对像实例。

  1. cout<<"Dyna Sizeof: "<<sizeof(((Init *))->a)<<endl; //C++98时借用实例对象获得非静态成员长度
  2. cout<<"Dyna Sizeof: "<<sizeof(Init::a)<<endl; //C++11支持直接获得

 

1.10 扩展的friend用法, friend时C++中比较特别的关键字,一方面它让程序员省下了很多代码,另一方面也破坏了OOP中的封装性,在C++11中做了改进,以保证更好的运用。

  1. class People;
  2. template<typename T> class Ploy;
  3.  
  4. template<typename T>
  5. class Ploy{
  6. public:
  7. friend T; //指定类的友元类,允许友元类访问本地参数
  8. private:
  9. string m{"smart"};
  10. };
  11.  
  12. class People{
  13. public:
  14. void ShowPara(Ploy<People> *p){
  15. cout<<"Ploy Data: "<<p->m<<endl;
  16. }
  17. };
  18.  
  19. //friend的扩展用法
  20. Ploy<People> ppe;
  21. People Pe;
  22. Pe.ShowPara(&ppe);

1.11 final和override控制, final用来限制基类虚函数的对应的派生类不能重写该虚函数,从而避免了某些接口被重写覆盖; override则指定了函数必须重载基类的虚函数,否则编译通不过,这就避免了某些输入名或者原型不匹配等错误的发生。

  1. class MathObject{
  2. public:
  3. virtual double Arith() = ;
  4. virtual void Print() = ;
  5. };
  6.  
  7. class Printable:public MathObject{
  8. public:
  9. double Arith() = ; //纯虚函数仅允许为0
  10. void Print() final{
  11. std::cout<<"Output is: "<< Arith() <<std::endl;
  12. }
  13. };
  14.  
  15. class Add2:public Printable{
  16. public:
  17. Add2(double a, double b):x(a), y(b){}
  18. double Arith() override{ //override指定函数为派生类的override(覆盖)函数,会进行检查
  19. return x+y;
  20. }
  21. // void Print(){} //编译会报错,因为父类声明了final,子类不允许重载
  22. private:
  23. double x, y;
  24. }

  

1.12 默认的模板参数,C++11中模板和函数一样,支持默认参数。

  1. //类模板 C++98就允许,不过定义有要求
  2. template<typename T1, typename T2 = int>class DefClass1{}; //允许,指定类模板的默认模板参数
  3. //template<typename T1 = int, typename T2> class DefClass2; //通不过编译,多个默认模板参数指定默认值时,必须遵守从右向做的原则
  4.  
  5. //函数模板 C++11添加
  6. template<typename T1, typename T2 = int>void DefFunc1(T1 a, T2 b);
  7. template<typename T1 = int, typename T2>void DefFunc2(T1 a, T2 b); //允许

  

1.13 外部模板, 外部模板实现依赖于C++98已有的特性,显示实例化。这样就可以实现一次实例,多次使用。

  1. //sundry.h
  2. template <typename T>void fun(T) {} //模板函数定义
  3.  
  4. //sundry1.cpp
  5. template void fun<int>(int); //模板实例化声明
  6. //sundry2.cpp
  7. extern template void fun<int>(int); //模板外部声明

1.14 局部或者匿名类型做模板实参, C++11支持匿名或者局部类型作为模板的实参,提供了更多的使用方法。

  1. template<typename T> class X{};
  2. template<typename T> void TempFunc(T t){};
  3. struct {int i;}b;
  4. typedef struct{int i;}B;
  5.  
  6. struct C{} c;
  7. X<B> x1;     //匿名结构体作为实参,不过只支持别名,不支持匿名结构体直接作为实参
  8. X<C> x2;      //局部变量作为实参
  9. TempFunc(b);   //匿名类型变量,C++11允许
  10. TempFunc(c);   //局部类型变量,C++11允许

  到现在为止,C++11的新基础特性中比较重要的部分差不多讲完了,从这些改动可以看出,C++11向着更方便,更强大的方向稳步前进,而且这些改动只是沧海一粟,如新的lambda表达式,类的构造函数的新实现,更加常态化的SFINAE,这些都值得研读,不过今天有点晚了,先到此为止,后面我会一边测试一边总结,感谢C++11委员会,也感谢本书作者详细的阐述,受用无穷!

  参考资料:

  《深入理解C++11:C++ 11新特性解析与应用》

C++ 11学习和掌握 ——《深入理解C++ 11:C++11新特性解析和应用》读书笔记(一)的更多相关文章

  1. c++学习书籍推荐《深入理解C++11 C++11新特性解析与应用》下载

    百度云及其他网盘下载地址:点我 编辑推荐 <深入理解C++11:C++11新特性解析与应用>编辑推荐:C++标准委员会成员和IBM XL编译器中国开发团队共同撰写,权威性毋庸置疑.系统.深 ...

  2. 【转】《深入理解C# 3.x的新特性》博文系列汇总

    [转]<深入理解C# 3.x的新特性>博文系列汇总 较之C# 2.0, C# 3.x引入了一系列新的特性,为我们编程带来很大的便利,通过有效地利用这些新特性,我们可以编写出更加简洁.优雅的 ...

  3. (数据科学学习手札111)geopandas 0.9.0重要新特性一览

    本文示例文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 就在几天前,geopandas释放了其最新正式版 ...

  4. (数据科学学习手札129)geopandas 0.10版本重要新特性一览

    本文示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 就在前不久,我们非常熟悉的Python地理 ...

  5. 2018.4.23 《深入理解Java虚拟机:JVM高级特性与最佳实践》笔记

    一.Java内存区域与内存溢出 1.程序计数器是一块较小的内存空间,它可看作是当前线程所执行的字节码的行号指示器.字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令.各条线程 ...

  6. java并发学习--第八章 JDK 8 中线程优化的新特性

    一.新增原子类LongAdder LongAdder是JDK8中AtomicLong的增强工具类,它与AtomicLong最大的不同就是:在多线程场景下,LongAdder中对单一的变量进行拆分成多个 ...

  7. ElasticSearch7.3学习(三十)----ES7.X SQL新特性解析及使用Java api实现sql功能

    一.ES7 sql新特性 1.1 数据准备 创建索引及映射 建立价格.颜色.品牌.售卖日期 四个字段 PUT /tvs PUT /tvs/_mapping { "properties&quo ...

  8. C++11学习

    转自: https://www.cnblogs.com/llguanli/p/8732481.html Boost教程: http://zh.highscore.de/cpp/boost/ 本章目的: ...

  9. 转:c++ 11 新特性

    声 明:本文源自 Danny Kalev 在 2011 年 6 月 21 日发表的<The Biggest Changes in C++11(and Why You Should Care)&g ...

随机推荐

  1. 图片轮播器bcastr4.swf“&”符号的问题

    bcastr4.swf是一个很不错的网页图片轮播器,我一直使用它作为网站首页图片轮播的控件. http://xiaogui.org/bcastr-open-source-flash-image-sil ...

  2. My Env

    Font -- YaHei Consolas Hybrid YaHei ConsolasAsume that we put the font file in /usr/share/fonts/myfo ...

  3. mysql 日期加减操作

    1. MySQL 为日期增加一个时间间隔:date_add() set @dt = now(); select date_add(@dt, interval 1 day);        -- add ...

  4. 用于svn添加当前目录下所有未追踪的文件,和删除所有手动删除的文件的脚本

    由于要经常用到类似与 git 中的 git add --all 这种操作,但是发现svn中并不支持类似的操作. 虽然可以使用 wildcard 进行匹配,但是 wildcard是在shell中进行匹配 ...

  5. Oracle新表使用序列(sequence)作为插入值,初始值不是第一个,oraclesequence

    Oracle新表使用序列(sequence)作为插入值,初始值不是第一个,oraclesequence 使用oracle11g插入数据时遇到这样一个问题: 1 --创建测试表-- 2 CREATE T ...

  6. ios 使用AFN上传图片到服务器

    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; manager.responseSe ...

  7. Java:通过反射复制父类字段到子类。

    有些时候需要建立子类继承于父类,尤其是java里面很多类是用mybatis generator生成的.通过父类构造子类,好像很麻烦,要逐个字段进行赋值(反正我没有找到其他好办法). 想到用反射复制的方 ...

  8. [To do]Appx Package installed, can't start at first time

    When installed partition tool & mkrcvcd as windows store app. it can't start at first time. the ...

  9. QT常见数据类型操作

    平常使用QStringList,都是通过at()访问其中的元素,然后试图也通过它修改元素,编译器报错,原来要使用下标访问修改: //accessRecList.at(3)=strSimilarity; ...

  10. 微信支付JsAPI

    https://pay.weixin.qq.com/wiki/doc/api/download/WxpayAPI_php_v3.zip 下载获取微信支付demo压缩包 打开压缩包,并将其中 Wxpay ...