目录
1. 在C++98中,标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定。
2. C++11扩大了用花括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,可添加等号(=),也可不添加。
3. 创建对象时可以使用列表初始化方式调用构造函数初始化
- struct T1
- {
- int a;
- int b;
- };
- class Date
- {
- public:
- Date(int year, int month, int day)
- : _year(year), _month(month), _day(day)
- { cout << "Date(int year, int month, int day)" << endl; }
-
- private:
- int _year;
- int _month;
- int _day;
- };
-
- void TestCpp98()
- {
- // C++ 98
- T1 t = {1,2};
- // T1 t2{1,2}; // error
- int arr1[3] = {1,2,3};
- // int arr2[3]{1,2,3}; // error
-
- Date d3(1,2,3); // C++98
- Date d4 = Date(1,2,3); // C++98
- // Date d{1,2,3}; // error
- // Date d2 = {1,2,3}; // error
- }
-
- void TestCpp11()
- {
- // // C++ 11
- T1 t = {1,2};
- T1 t2{1,2}; // C++11
-
- int arr1[3] = {1,2,3};
- int arr2[3]{1,2,3}; // C++11
-
- Date d{1,2,3}; // C++11
- Date d2 = {1,2,3}; // C++11
- Date d3(1,2,3); // old style 效果同上
- int i = 1;
- int i2 = {1}; // C++11
- int i3{1}; // C++11
- }
自定义类型使用花括号初始化对象时,自动调用对应的构造函数。
对于自定义类型和内置类型都可以用{}初始化,且"="可省略。
std::initializer_list一般是作为构造函数的参数,C++11对STL中的不少容器就增加 std::initializer_list作为参数的构造函数,这样初始化容器对象就更方便了。也可以作为operator= 的参数,这样就可以用大括号赋值。
- // C++11
- vector<int> v = {1,2,3,4,5};
- vector<int> v2{1,2,3,4,5};
- vector<int> v3({1,2,3,4,5});
- v = {1,2,3,4}; // 调用以initializer_list为参数的operator=();
-
- vector
v4 = {{2022,11,27}, {2022,11,22}}; - map
int> m = { {"right", 1}, {"left", 1} };
以上都调用了vector和map以std::initializer_list为参数的构造函数。其中v4和m分别使用{}调用Date的对应参数构造函数和pair的构造函数。C++11之后,pair的构造不再必须使用make_pair,使用{}调用其构造函数即可。
八个月前看C++ Primer时,碰巧写过一篇博客,此处略了。
范围for的底层原理就是编译器将范围for替换为迭代器循环访问,因为迭代器对于STL容器来说使用上有统一性,所以可以无脑替换。对于原生数组的范围for,就是替换为原生指针类型,和vector一个原理,因为vector迭代器的底层就是原生指针。因为原生指针完全可以满足迭代器的所有要求。
C和C++98中的NULL被定义为字面量0,这样NULL既能表示指针常量,又能表示整型常量,存在模糊问题和安全隐患。故C++11中引入nullptr,表示空指针。(void*(0))
STL新增了array(定长数组容器,可理解为定长vector),forward_list(单链表),unordered_map(底层为哈希表的关联式容器),unordered_set,unordered_multimap(允许键值重复的哈希表关联式容器),unordered_multiset。
cbegin cend crbegin crend 右值引用产生的移动构造,移动赋值,右值引用产生的push_back,insert等。以及应用可变参数模板产生的emplace_back,emplace,在某些场景下可以提高效率。
简单回顾一下,拷贝构造和拷贝赋值用于左值对象的拷贝和赋值。而移动构造和移动赋值用于右值对象的拷贝和赋值,典型的比如函数传值返回深拷贝对象,还有函数传参时,如果是右值,也就是将亡值,完全可以进行资源转移,而不是深拷贝。
C++11之前,C++98时,有6个默认成员函数:构造函数,析构函数,拷贝构造函数,拷贝赋值重载(operator=),取地址运算符重载函数(operator&),const对象取地址运算符重载函数(operator&)。重点是前四个,后两个几乎不用主动实现。默认成员函数就是我们不实现,编译器会自动实现的成员函数(注意我们实现了拷贝构造,就不会自动生成构造了,因为都属于构造)
C++11新增了两个:移动构造函数和移动赋值运算符重载函数。
它们的生成条件有些不同:
如果你没有自己实现移动构造函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个。那么编译器会自动生成一个默认移动构造。
默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造, 如果实现了就调用移动构造,没有实现就调用拷贝构造。
如果你没有自己实现移动赋值重载函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个,那么编译器会自动生成一个默认移动赋值。
默认生成的移动赋值重载函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动赋值,如果实现了就调用移动赋值,没有实现就调用拷贝赋值。(默认移动赋值跟上面移动构造完全类似)
C++11允许在类定义时给成员变量设定初始缺省值,所有构造函数的默认初始化列表会使用这些缺省值对成员变量初始化。
C++11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数,但是因为一些原 因这个函数没有默认生成。比如:我们提供了拷贝构造,就不会生成移动构造了,那么我们可以 使用default关键字显示指定默认移动构造生成。 string(string&& s) = default;
如果能想要限制某些默认函数的生成,在C++98中,是将该函数设置成private,并且只声明不定义,这样只要其他人想要调用就会报错。在C++11中更简单,只需在该函数声明加上=delete即 可,该语法指示编译器不生成对应函数的默认版本,称=delete修饰的函数为删除函数。
1. final:修饰虚函数,表示该虚函数不能再被重写
2. override: 检查派生类虚函数是否重写了基类某个虚函数,如果没有重写则编译报错。
没心情学这个,就是C++11之前,函数模板和类模板的模板参数的数量是一定的,C++11新增的可变参数模板可以让模板参数接收任意数量的实参,作用是很大的,比如emplace等提高性能的地方都用了可变参数模板。但是遗憾的是我没心情学啊