C++11新特性
- auto关键字(C++11)基于范围的for循环(C++11). 指针空值nullptr(C++11)
- C++动态内存管理
- 序列式容器 array forward_list;
- 继承和多态:final override
- delete:不生成默认的成员函数
- default:强制编译器生成默认的成员函数
- 智能指针:unique_ptr,shared_ptr,weak_ptr
- 哈希结构的关联式容器:unordered系列
统一的初始化
C++98中标准允许使用花括号{}对数组元素进行统一的列表初始值设定
int array1[] = {1,2,3,4,5};
int array2[5] = {0};
对于vector容器来说不能这样初始化
vector<int> v{1,2,3,4,5};
就无法通过编译,导致每次定义vector时,都需要先把vector定义出来,然后使用循环对其赋初始值,非常不方便。
C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,可添加等号(=),也可不添加。
内置类型花括号{}初始化
// 内置类型变量
int x1 = { 10 };
int x2{ 10 };
int x3 = 1 + 2;
int x4 = { 1 + 2 };
int x5{ 1 + 2 };
int x6{ x1 + x2 };
// 数组
int arr1[5] {1, 2, 3, 4, 5};
int arr2[]{1, 2, 3, 4, 5};
// 动态数组,在C++98中不支持
int* arr3 = new int[5]{1, 2, 3, 4, 5};
// 标准容器
vector<int> v{ 1, 2, 3, 4, 5 };
map<int, int> m{ { 1, 1 }, { 2, 2, }, { 3, 3 }, { 4, 4 } };
单个自定义类型列表初始化
class Point
{
public:
Point(int x = 0, int y = 0)
: _x(x), _y(y)
{}
private:
int _x;
int _y;
};
int main()
{
//两种初始化都可以
Point p{ 1, 2 };
Point p2(1, 2);
return 0;
}
多个自定义类型列表初始化
多个对象想要支持列表初始化,需给该类(模板类)添加一个带有initializer_list类型参数的构造函数即可。注意:initializer_list是系统自定义的类模板,该类模板中主要有三个方法:begin()、end()迭代器以及获取区间中元素个数的方法size()。
template<class T>
class vector
{
public:
vector()
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{}
vector(initializer_list<T>l)
:_start(new T[l.size()])
{
_finish = _start;
for (auto e : l)
{
*_finish++ = e;
}
}
private:
T* _start;
T* _finish;
T* _endofstorage;
};
变量类型推导
auto推导
decltype类型推导
auto使用的前提是:必须要对auto声明的类型进行初始化,否则编译器无法推导出auto的实际类型
template<class T1,class T2>
//返回的时候,返回T1和T2都不行,应该返回T1+T2后的值的类型
auto Add(const T1& left, const T2& right)
{
return left + right;
}
如果能用加完之后结果的实际类型作为函数的返回值类型就不会出错,但这需要程序运行完才能知道结果的
实际类型,即RTTI(Run-Time Type Identification 运行时类型识别)。
typeid
只能查看类型不能用其结果类定义类型dynamic_cast
只能应用于含有虚函数的继承体系中
所以需要新的关键字
decltype是根据表达式的实际类型推演出定义变量时所用的类型,例如:返回值类型推演
//此处auto为占位符
//返回值类型追踪
auto Add( T1& left, T2& right)->decltype(left+right)
{
return left + right;
//ret = left + right;
}
int main()
{
int a = 1;
double b = 2.0;
cout<< Add(a, b);
return 0;
}
范围for循环
范围for
final和override
多态中总结过
智能指针
智能指针总结
新增容器----静态数组array,forward_list以及unordered系列
委派构造函数
所谓委派构造函数:就是指委派函数将构造的任务委派给目标构造函数来完成的一种类构造的方式。
在初始化列表中调用”基准版本”的构造函数称为委派构造函数,而被调用的”基准版本”则称为目标构造函数。
注意:构造函数不能同时”委派”和使用初始化列表。
class Info {
public:
Info()
: _type(0)
, _name('a')
{
InitRSet();
}
Info(int type)
:Info()
//不能再在初始化列表中初始化其它的成员变量
//,_type(type)
{
//InitRSet();
_type = type;
}
Info(char type)
:Info()
{
//InitRSet();
_type = type;
}
private:
void InitRSet()
{
//初始化其他变量
}
private:
int _type;
char _name;
//...
};
- 委派构造函数同时可以是目标构造函数
- 切记:环状委派 依然可以通过编译但是会右栈溢出
右值引用
默认函数控制
C++11让程序员可以控制是否需要编译器生成那些默认生成的函数
显式缺省函数
在C++11中,可以在默认函数定义或者声明时加上=default,从而显式的指示编译器生成该函数的默认版本,用=default
修饰的函数称为显式缺省函数。
class A
{
public:
A(int a): _a(a)
{}
// 显式缺省构造函数,由编译器生成
A() = default;
// 在类中声明,在类外定义时让编译器生成默认赋值运算符重载
A& operator=(const A& a);
private:
int _a;
};
A& A::operator=(const A& a) = default;
int main()
{
A a1(10);
A a2;
a2 = a1;
return 0;
}
删除默认函数
如果能想要限制某些默认函数的生成,在C++98中,是该函数设置成private,并且不给定义,这样只要其他人想要调用就会报错。在C++11中更简单,只需在该函数声明加上=delete即可,该语法指示编译器不生成对应函数的默认版本,称=delete修饰的函数为删除函数。
class A
{
public:
A(int a): _a(a)
{}
// 禁止编译器生成默认的拷贝构造函数以及赋值运算符重载
A(const A&) = delete;
A& operator(const A&) = delete;
private:
int _a;
};
int main()
{
A a1(10);
// 编译失败,因为该类没有拷贝构造函数
//A a2(a1);
// 编译失败,因为该类没有赋值运算符重载
A a3(20);
a3 = a2;
return 0;
}
注意:避免删除函数和explicit一起使用