更加简单的初始化方式
C++11提供在类中定义类的数据成员,可以直接在成员之后添加=[缺省值],当通过编译器自动生成的默认构造函数初始化对象时,对应的数据成员就会被初始化成对应的缺省值。
class Test
{
public:
int _t = 100;
};
int main()
{
Test t; //初始化完成后,t._t的值为100
return 0;
}
更加强大的{}
在C++98中,数组可以使用{}来进行初始化,对自定义类型是不可以的。
在C++11中,{}的使用范围变得更广,可以使用{}来初始化一个vector/list/string/map/set/multimap/multiset/unordered_map/unordered_set,在初始化时,可以添加=号,也可以不适用=号。
int main()
{
//c++11中,下面的方式是可以的
std::vector<int> v1 = { 1,2,3 };
std::vector<int> v2{ 1,2,3 };
std::list<int> l1 = { 1,2,3 };
std::list<int> l2{ 1,2,3 };
std::string s1 = { "hello" };
std::string s2{ "hello" };
std::map<int, int> m1 = { {1,1}, {2,2}, {3,3} };
std::map<int, int> m2{ {1,1}, {2,2}, {3,3} };
std::set<int> set1 = { 1,2,3 };
std::set<int> set2{ 1,2,3 };
std::multimap<int, int> mt_map1 = { {1,1},{2,2},{3,3} };
std::multimap<int, int> mt_map2{ {1,1},{2,2},{3,3} };
std::multiset<int> mt_set1 = { 1,2,3 };
std::multiset<int> mt_set2{ 1,2,3 };
std::unordered_map<int, int> un_map1 = { {1,1}, {2,2}, {3,3} };
std::unordered_map<int, int> un_map2{ {1,1}, {2,2}, {3,3} };
std::unordered_set<int> un_set1 = { 1,2,3 };
std::unordered_set<int> un_set2{ 1,2,3 };
return 0;
}
注意:经过测试,stack和queue是不适用于该特性的。
auto关键字
C++11中可以使用auto来表明该变量的类型由编译器在编译时期推导得出。
注意:
- 使用auto关键字必须进行初始化。
- 使用const/voliate关键字初始化auto类型变量时,编译器推导出的变量不具有const/voliate的限制。
auto不能进行推导的场景
- auto不能作为函数形参
- auto不能定义为类的非静态成员变量
- auto不能用来声明数组
- 实例化模板时,不能使用auto来作为实例化的类型
范围for循环
C++11提供一种基于迭代器的语法糖遍历方式,它可以让程序员遍历一个有范围的容器时更加简单。
int main()
{
std::vector<int> v = {1,2,3};
for(auto& e:v)
{
//这样即可遍历v中的每一个元素,e则就是元素的引用
}
return 0;
}
显式的缺省类的默认成员函数
当编写一个类想要使用编译器自动生成的默认成员函数时,只需要在函数的声明/定义时在函数的后面加上=default即可。
class Test
{
public:
Test() = default;
Test& operator=(sonst Test& t);
};
Test& Test::operator=(sonst Test& t) = default;
完全删除某个默认成员函数
当编写代码的过程中想要完全删除某一个默认成员函数时,在该函数的声明后面加上=delete即可。
class Test
{
public:
Test() = delete;
Test& operator=(const Test& t) = delete;
};
注意:
- =delete只能出现在函数的第一个声明中。
final和override关键字
final关键字
- final修饰虚函数,表示该虚函数不可以在派生类中进行重写。否则编译不通过。
- final修饰类,表示该虚函数不可以再被继承。否则编译不通过。
class Test
{
public:
virtual void HelloWorld() final
{
//该函数不能在派生类中被重写,若重写,即报错
}
};
class Test1 final
{
//该类不能再被继承
public:
Test1()
{}
}
override关键字
该关键字用于基类虚函数,用来确保派生类中对继承自基类的虚函数进行了重写,若派生类没有进行重写,则就会编译报错。
右值引用
右值引用的意义就在于消除了多种场景下进行的不必要的开销,例如接收函数返回值时进行的一次拷贝构造,右值引用可以看作是对该行为的一种优化方式。
左值&右值
左值
- 再赋值表达式中,出现在=左边的就是左值,而出现在=右边的不一定是右值
- 可以取地址、有名字的就是左值,否则就是右值
右值:在C++11中右值由两个概念组成:纯右值&将亡值
- 纯右值:纯右值是C++98中右值的概念,用于识别临时变量和一些不跟对象相关联的值
- 将亡值:C++11新增跟右值引用相关的表达式,这些表达式通常是将要被移动的对象。例如:返回值右值引用T&&,std::move的返回值,转换为T&&的类型转换函数的返回值
std::string Test()
{
std::string str("hello");
return str;
}
int main()
{
std::string&& str = Test(); //右值引用引用右值
const std::string& str1 = Test(); //使用左值引用(普通引用)引用右值
return 0;
}
std::move()
该接口的作用是将一个左值强制类型转换为右值引用,通过右值引用使用该值,实现移动语义。
完美转发
在传递参数时,有时候可能会使参数的属性发生变化,完美转发即就是不改变参数的任何属性进行传参。
void func(const int n)
{}
int main()
{
func(3); //此处传递的参数为右值 但函数若进行接受就会将该参数变为左值
func(std::forward(3)); //这样传递参数依旧是右值 但是右值要用const来接收
return 0;
}
线程支持
C++11对线程进行了支持,在并发编程时不需要第三方库,直接使用标准库的<thread>头文件。
原子操作
C++11引用了一系列原子操作,包含在标准库文件<atomic>中。