因为偶然的机会,在图书馆看到《深入理解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库的支持情况,不过测试部分显示未定义。

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

  

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

const char * Stanard_Macros(void)
{
//......
return __func__; //返回值:Stanard_Macros
}

  

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

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

 

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

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

 

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

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

  

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

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语句产生异常的)的发生。

const char * Stanard_Macros(void) noexcept     //相当于noexcept(true), 如果有异常会发生,不会传播和扩散,编译会调用std::terminate()来终止程序运行

const char * Stanard_Macros(void) noexcept(false) //noexcept中可以为结果为bool型的表达式

  

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

class Mem{
public:
Mem(int i): m(i){};
~Mem(){};
const char *ShowMem(void){ std::cout<<"Mem: "<<m<<" ";
return __func__;
};
private:
int m{};
}; //快速初始化
//初始化列表优于就地的列表初始化
class Init{
public:
Init(): a(){}; Init(int d): val('G'), a(d){}; //初始化列表实际效果后作用,效果上优于列表初始化
// ~Init(){ throw 1; };
~Init(){};
const char * showPara(std::string str);
int a;
private:
char val{'g'};       //成员变量的快速初始化
Mem mem{};
std::string name{"Init"};
}; //C++的成员变量快速初始化
Init init1{}; //C++11的统一列表初始化
Init init2;
init1.showPara("init1: "); //init1: 5 init1: G name :Init Mem: 1 mem :ShowMem
init2.showPara("init2: "); //init2: 0 init2: g name :Init Mem: 1 mem :ShowMem

  

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

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

 

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

class People;
template<typename T> class Ploy; template<typename T>
class Ploy{
public:
friend T; //指定类的友元类,允许友元类访问本地参数
private:
string m{"smart"};
}; class People{
public:
void ShowPara(Ploy<People> *p){
cout<<"Ploy Data: "<<p->m<<endl;
}
}; //friend的扩展用法
Ploy<People> ppe;
People Pe;
Pe.ShowPara(&ppe);

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

class MathObject{
public:
virtual double Arith() = ;
virtual void Print() = ;
}; class Printable:public MathObject{
public:
double Arith() = ; //纯虚函数仅允许为0
void Print() final{
std::cout<<"Output is: "<< Arith() <<std::endl;
}
}; class Add2:public Printable{
public:
Add2(double a, double b):x(a), y(b){}
double Arith() override{ //override指定函数为派生类的override(覆盖)函数,会进行检查
return x+y;
}
// void Print(){} //编译会报错,因为父类声明了final,子类不允许重载
private:
double x, y;
}

  

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

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

  

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

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

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

template<typename T> class X{};
template<typename T> void TempFunc(T t){};
struct {int i;}b;
typedef struct{int i;}B; struct C{} c;
X<B> x1;     //匿名结构体作为实参,不过只支持别名,不支持匿名结构体直接作为实参
X<C> x2;      //局部变量作为实参
TempFunc(b);   //匿名类型变量,C++11允许
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. Linux操作系统备份之三:通过二进制拷贝(dd)方式实现Linux操作系统数据的备份

    前面有两篇文章,<Linux操作系统备份之一:使用LVM快照实现Linux操作系统数据的在线备份>和<Linux操作系统备份之二:通过tar拷贝分区实现Linux操作数据的在线备份& ...

  2. JSP中文乱码总结

    大家在JSP的开发过程中,经常出现中文乱码的问题,可能一至困扰着大家,现把JSP开发中遇到的中文乱码的问题及解决办法写出来供大家参考.首先了解一下Java中文问题的由来: Java的内核和class文 ...

  3. c#-快速排序-算法

    快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists). 步骤为: 1.从数列中挑出一个元素,称为 "基准"(p ...

  4. Good Bye 2015 D. New Year and Ancient Prophecy

    D. New Year and Ancient Prophecy time limit per test 2.5 seconds memory limit per test 512 megabytes ...

  5. XML Schema choice 元素

    XSD : <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sch="http://w ...

  6. crm软件如何实现企业智能化管理?

    互联网技术的发展,让企业越来越重视客户的感知体验,企业只有适应并接受再逐步转向智能化发展模式,才能在市场竞争中取胜不被淘汰.选择一款适宜企业自身发展的CRM系统,根据自身的具体情况随需而定,企业才能更 ...

  7. QT数据库操作

    浏览: 在QSqlQuery类中当执行exec()后会把指针放在记录集中第一个记录之上,所以需要调用QSqlQuery::next()来获取第一个数据,下面通过循环体来遍历所有表中的数据. while ...

  8. ThreadLocal是什么?保证线程安全

    早在JDK 1.2的版本中就提供Java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路.使用这个工具类可以很简洁地编写出优美的多线程程序. 当使 ...

  9. STM32F429i-DISCO FreeRTOS keil STM32CubeMX

    目标: 在STM32F429 Disco开发板上用FreeRTOS双线程点亮双闪led. 准备: 0. STM32F429i-DISCO 1. keil ARMMDK 5.13 2. STM32Cub ...

  10. requirejs学习