void fun() noexcept {};
void fun() final;//refuse
void fun() override;//must
默认模板参数:从右往左定义
继承构造函数 using base::f,派生类无法使用基类的非虚函数。所以using这一语法也可以被用到构造函数中。但要注意的是如果构造函数是私有的或者是虚继承,派生类将不会提供默认构造函数。同时我们还要解决继承冲突问题,方法是加上派生类的自定义构造函数。
委派构造函数:用于解决构造函数中调用重复函数的问题。但其自身不能有初始化列表。需要注意的是目标构造函数总是先于委派构造函数执行。可以进行链式委派,但要避免出现委派环。
class info{
public:
info(){Initreset();}//目标构造函数
info(char a):info(){this.a = a;}//委派构造函数
info(int b): info(){this.b = b;}
private:
void Initreset(){}
char a{'a'};
int b{1};
}
完美转发:这里涉及到引用折叠(一旦定义中出现左值引用,引用折叠总是优先折叠为左值引用),保证引用的类型不会改变。定义为一个函数模板向它调用的函数传递参数时保持参数的左值或右值。
模板的别名:
template<typename T> using MapString = Map<T, char*>;
MapString<int> number;
decltype:根据也只能根据表达式推导类型。一般和using连用,为该类型定义别名。而typeid(变量).name打印该变量名字。这用在编译和调试,或者缩短类型名时很有作用。
decltype推导四规则:
1. 如果e是一个没有带括号的标记符表达式或者类成员访问表达式,那么的decltype(e)就是e所命名的实体的类型。此外,如果e是一个被重载的函数,则会导致编译错误。
2. 否则 ,假设e的类型是T,如果e是一个将亡值,那么decltype(e)为T&&
3. 否则,假设e的类型是T,如果e是一个左值,那么decltype(e)为T&。
4. 否则,假设e的类型是T,则decltype(e)为T。
而(e)标识为一个左值。则对应规则3。
int i=1;
decltype((i)) b = 2;//这里返回左值引用。
对于cv限制符,decltype可以带走推导,但是其成员不会继承cv限制符。
volatile关键字:用于表示该关键字修饰的变量可以被编译器未知的因素更改,因此编译器对访问该变量的代码就不再进行优化,当要求使用 volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据。
强枚举类型:type class typename{};或者 type class typename:int {};
智能指针:这里主要介绍unique_ptr和shared_ptr,这两个指针类型实际上是模板类型,在使用前要先实例化。
unique_ptr:顾名思义,这是一个不能与他人分享对象内存的指针。
unique_ptr<int> p1(new int(11));//使用前要像一般指针一样分配内存。
unique_ptr<int> p2 = p1;//不能共享p1的内存
unique_ptr<int> p3 = move(p1);//可以通过move转移所有权
shared_ptr:顾名思义,这是一个可以与他人分享内存的指针类型,他内置了一个引用计数器,只有当计数器为0时才会释放内存。
shared_ptr<int> p1(new int(11));
shared_ptr<int> p2 =p1;
p1.reset();//只有当指针调用reset函数时释放内存。
lambda表达式:
语法格式:[capture](parameter)mutable->type{statement}
capture为捕捉列表,捕捉在上下文中出现的变量以供lambda表达式使用。
捕捉语法如下:
1. [var]表示值传递方式捕捉变量var;
2. [=]表示值传递方式捕捉所有父作用域的变量(包括this);
3. [&var]表示引用传递捕捉变量var;
4. [&]表示引用传递方式捕捉所有父作用域的变量(包括this);
5. [this]表示值传递方式捕捉当前的this指针。
要注意的是捕捉时不能出现重复变量,即如果你选择捕捉全部的引用类型,就不能又单独捕捉类型a。
parameter为函数调用时传入的参数列表。
mutable修饰符:默认情况下,Lambda函数总是一个const函数,mutable可以取消其常量性。在使用该修饰符时,参数列表不可省略(即使参数为空);
要注意的是:
按值传递的捕捉方式传进去的是一个常量,一旦初始化就不会再改变。按引用传递仍可以使用父作用域中的值。
由于默认情况下的lambda表达式是const函数,则其不能改变参数的值。
C++函数闭包:
闭包是带有上下文的函数。说白了,就是有状态的函数。一个函数,带上了一个状态,就变成了闭包了。那什么叫 “带上状态” 呢? 意思是这个闭包有属于自己的变量,这些个变量的值是创建闭包的时候设置的,并在调用闭包的时候,可以访问这些变量。所以上文提到的lambda表达式是闭包的一种。而更直接的是重载operator()函数。
追踪返回类型:function()->type