初始化
C++ 11扩展了大括号{}的适用范围,既可以用于基本类型,也可以用于自定义类型:
int x = {5};
double y{3.5};
short quar[5]{1, 2, 3, 4, 5};
int* p = new int[5]{1, 2, 3, 4, 5};
创建对象时,也可以使用大括号链表来调用构造函数:
class Stump
{
Public:
Stump(int r, double w) : roots(r), weight(w){}
Private:
int roots;
double weight;
};
Stump s1(3, 4.5); // old style
Stump s2{3, 4.5}; // new style
Stump s3 = {3, 4.5}; // new style
注意:使用初始化列表可以防止向下转型,如:
char c1 = 1.57e27; // double-to-char, undefined behavior
char c1{1.57e27}; // double-to-char, compile error
std::initializer_list可以作为函数参数,如果一个类中的构造函数使用了这种方法,则其他函数将不能再使用其作为参数,这是为了防止调用二义性。
Initializer_list模板类提供了两个成员函数begin()和end(),用来指定列表的范围,如:
double sum(std::initializer_list<double> il)
{
double total = 0;
for(auto p = il.begin(); p != il.end(); p++)
total += *p;
return total;
}
double total = sum({1, 2.5, 8.3, 2.2, 1.0});
声明
C++提供了多种简化声明的方式,尤其在使用模板时更加方便。
1 auto
用来实现自动类型推断,如:
auto i = 112; // i is type int
auto pt = &i; // pt is type int*
double fm(double, int);
auto pf = fm; // pf if type double(*)(double, int);
用于模板时形式简洁,如:
for(std::initializer_list<double>::iterator p = il.begin(); p != il.end(); p++)
改写为:
for(auto p = il.begin(); p != il.end(); p++)
2 decltype
将变量的类型指定为表达式的类型。
decltyte (x) y; 将y设为与x相同的类型,其中x是一个表达式。
3 返回类型后置
在函数名和参数列表后面指定返回类型。
double f1(double int); // return double type
auto f2(double, int) -> double; // new syntax, return double type
如果结合上模板表示返回类型,那就更好了,如下:
template<typename T, typename U>
auto eff(T t, U u) -> decltype(T * U)
{
}
4 模板别名
using =
C++中创建别名一般用typedef,如:
typedef std::vector<std::string>::iterator itType;
还可以这样做:
using itType = std::vector<std::string>::iterator;
5 nullptr
空指针
之前,C++使用0表示空指针,同样的0既可以表示整型,又可以表示空指针,比较混乱;新增的nullptr是指针类型,不能转换为整型。为了兼容性,C++目前仍然允许0表示空指针,即nullptr == 0的结果为true。
二者的差别在于,using可以使模板具体化,如:
using arr = std::array<T, 12>;//此时typedef不行。
4 智能指针
C++ 11摒弃了auto_ptr,新增了三种:unique_ptr、shared_ptr、weak_ptr。
5 异常
之前C++的语法中可以指出函数可能引发哪些异常,如:
void f1(int) throw(bad_alloc); // 可能抛出bad_alloc异常
void f2(long long) throw(); // 不抛异常
C++摒弃了异常规范,新增了如下
Void f3(short, short) noexcept; // 不抛异常
6 作用域内枚举
传统的C++枚举的作用域在所属的域内,就是说同一作用域内不能出现两个同名的枚举变量。
C++ 11新增了一种枚举,使用class或者struct定义:
enum Old{yes, no}; // old style
enum class New{yes, no}; // new style
enum struct New{yes, no}; // new style
由于允许同名存在,因此引用时需要使用枚举名限定:New::yes。
7 对类的修改
在扩展类的设计方面,C++ 11很多改进,比如允许构造函数被继承、彼此调用、移动构造函数、移动赋值运算符等。
7.1 显示转换运算符
早期的C++会导致自动类型转换,比如:
class Plebe
{
Plebe(int);
explicit Plebe(double);
...
};
Plebe a, b;
a = 5; //发生隐式类型转换,实则调用Plebe(5);
b = 0.5; //不允许
b = Plebe(0.5); //允许
C++ 11扩展了explicit,使得可以如下这样做:主要是针对转换函数:
比如:
operator int() const;
explicit operator double() const;
int n = a; // allow
double x = b; // not allow
x = double(b); // allow
7.2 类内成员初始化
class Session
{
int mem = 10;
double mem2{2.35};
...
};
每天进步一点点,就是——拥有水滴石穿的坚持;懂得聚沙成塔的积累;磨练坚韧不拔的意志;学习脚踏实地的奋斗;提升立世做人的技巧;突破自我设限的障碍。
—戴明博士