C++11新特性
C++11新特性非常的多,就一个简单的特性如果要讲解的很清楚并附上事例可能就需要写很多(个人觉着文章太长不利于理解),本片只大概介绍部分特性,以后有机会再针对个别特性做深入解释。以下只是个人在使用过程中觉着经常使用到的部分,现在做如下解释,错误之处望指正
1、右值和move语义
C++11 增加一个新的非常数引用(reference)类型,称作右值引用(R-value reference),标记为T &&。右值引用所引用的临时对象可以在该临时对象被初始化之后做修改,这是为了允许 move 语义,具体可以参见【原】C++ 11右值引用
注:stl中的容器都支持move语义,因此返回局部变量的时候效率不在是问题
2、POD定义的修正(plain old data)
一个极简的类型或结构符合以下定义:极简的默认建构式。这可以使用默认建构式语法,例如SomeConstructor() = default;
(1).极简的复制建构式,可使用默认语法(default syntax)
(2).极简的赋值操作符,可使用默认语法(default syntax)
(3).极简的解构式,不可以是虚拟的(virtual)
一个标准布局(standard-layout)的类型或结构符合以下定义:
(1).对所有non-static成员有相同的访问控制(public, private, protected)
(2).没有虚函数
(3).没有虚拟基类
(4).只有符合标准布局的基类
(5).没有和第一个定义的non-static成员相同类型的基类
(6).若非没有带有non-static成员的基类,就是最底层(继承最末位)的类型没有non-static数据成员而且至多一个带有non-static成员的基类。基本上,在该类型的继承体系中只会有一个类型带有non-static成员。
(7).只有非静态的(non-static)数据成员,且这些成员也是符合标准布局的类型
3、初始化列表
在引入C++ 11之前,只有数组能使用初始化列表。在C++ 11中一下都是合法的:
1 int a{5};
2 char c{'X'};
3 int p[5] = {1, 2,3, 4, 5};
4 vector vctTemp{1, 2, 3};
5 CPerson person{10, "Mike"};
6 int b = 5.3; // b赋值成5,发生了窄转换
7 int d{5.3}; // 会提示编译错误,避免了窄转换
map m_map = {{"test",1},{"test2",2}};//不需要构造键值对
vector test()
{
return{"1","2","3"};//列表初始化返回值
}
4、类型推导
有被明确初始化的变量可以使用 auto 关键字,decltype 能够被用来在编译期决定一个表示式的类型
auto someStrangeCallableType = boost::bind(&SomeFunction, _2, _1, someObject);
someStrangeCallableType 的类型就是模板函数 boost::bind 对特定引数所回返的类型。作为编译器语义分析责任的一部份,这个类型能够简单地被编译器决定,但用户要通过查看来判断类型就不是那么容易的一件事了
int someInt;
decltype(someInt) otherIntegerVariable = 5;//变量类型为int
decltype 所表示的类型可以和 auto 推导出来的不同
const std::vector v(1); auto a = v[0];// a 為 int 型別
decltype(v[0])b; // b 為 const int& 型別,即 std::vector::operator[](size_type)const 的回返型別
auto c = 0; // c 為 int 型別
auto d = c; // d 為 int 型別
decltype(c) e; // e 为 int 型別,c实际的型別
decltype((c)) f = e; // f 为 int& 型別,因 为(c)是左值
decltype(0) g; // g为int型別,因为0是右值
5、Lambda函数与表示式
当使用 C++ 标准程序库算法函数诸如 sort 和 find,用户经常希望能够在算法函数调用的附近定义一个临时的述部函数(又称谓词函数,predicate function)
C++ 11中的Lambda表达式用于定义并创建匿名的函数对象,以简化编程工作。Lambda的语法形式如下:
[函数对象参数] (操作符重载函数参数) mutable或exception声明 ->返回值类型 {函数体}。可以看到,Lambda主要分为五个部分:[函数对象参数]、(操作符重载函数参数)、mutable或exception声明、->返回值类型、{函数体}。下面分别进行介绍。
(1)、[函数对象参数],标识一个Lambda的开始,这部分必须存在,不能省略。函数对象参数是传递给编译器自动生成的函数对象类的构造函数的。函数 对象参数只能使用那些到定义Lambda为止时Lambda所在作用范围内可见的局部变量(包括Lambda所在类的this)。函数对象参数有以下形 式:
1、空。没有使用任何函数对象参数。
2、=。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。
3、&。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)。
4、this。函数体内可以使用Lambda所在类中的成员变量。
5、a。将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符。 6、&a。将a按引用进行传递。
7、a, &b。将a按值进行传递,b按引用进行传递。
8、=,&a, &b。除a和b按引用进行传递外,其他参数都按值进行传递。
9、&, a, b。除a和b按值进行传递外,其他参数都按引用进行传递。
(2)、(操作符重载函数参数),标识重载的()操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如:(a,b))和按引用(如:(&a,&b))两种方式进行传递。
(3)、mutable或exception声明,这部分可以省略。按值传递函数对象参数时,加上mutable修饰符后,可以修改按值传递进来的拷贝 (注意是能修改拷贝,而不是值本身)。exception声明用于指定函数抛出的异常,如抛出整数类型的异常,可以使用throw(int)。
(4)、->返回值类型,标识函数返回值的类型,当返回值为void,或者函数体中只有一处return的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略。
(5)、{函数体},标识函数的实现,这部分不能省略,但函数体可以为空。
使用qt的时候,connect的槽函数支持lambda表达式
for_each(vctTemp.begin(), vctTemp.end(), [&](int v)mutable{ cout << v+a << endl; a++; });//以引用方式传递作用域内所有可见的局部变量(包括this)
6、强类型枚举
在标准C++中,枚举类型不是类型安全的,C++03 唯一提供的安全机制是一个整数或一个枚举型值不能隐式转换到另一个枚举别型.
enum class typeA{a1 = 1, a2};
a1 == 1;语句会报错
枚举的名称全数暴露于一般范围中,因此两个不同的枚举,不可以有相同的枚举名
enum A{a, b};enum B{a, c};//美剧中的a是非法的
7、显式类型转换子(explicite) 防止参数的隐式转换
8、静态assertion
static_assert( 3.14
< GREEKPI && GREEKPI
< 3.15, "GREEKPI is inaccurate!" )
;参数1如果为false,则弹出参数2这个字符串
9、constexpr:constexpr可以说是对const变量的扩展,它只是约束const变量的右侧的式子必须能在编译时就能算出值
10、类型别名
typedef int (addptr*)(int a,int b);
C++11中可以这样:using addptr = int (int,int);
11、nullptr
nullptr是C++ 11中新加的一个关键字,用于标识空指针。引入nullptr后,可以解决某些函数重载时的二义性问题
如果存在方法void f(int)和方法void f(char *p),则调用f(0)时,在C++ 98中编译失败,有二义性编译器会不错,但是在C++11中调用f(int),方法f(char *)调用方式:f(nullptr)。
12、默认或者禁用
当我们定义了自己的带参数的构造函数时,编译器将不再生成默认的构造函数,如果此时想使用默认的构造函数,则必须显式地声明并定义不带参数的构造函数。在C++ 11中,我们可以使用default关键字来表明我们希望使用默认的构造函数。类似的,当我们不想外部使用编译器自动生成的构造函数或赋值函数时,我们一般需要将其声明成protected或private的。在C++ 11中,我们可以使用delete关键字来表明我们不希望编译器生成默认的构造函数或赋值函数
CPerson() = default; //CPerson的构造函数
CPerson(const CPerson &person) = delete;//CPerson的拷贝构造函数
13、模板右边双括号
在C++ 98中,vector> vctTemp是一个非法的表达式,模板的两个右尖括号中间必须有空格,但C++11中该表达式合法
引用文章