auto
是一个存储类型说明符,用于实现自动类型推断。
auto maton = 112;// int
auto pt = &maton // int *
for(std::initializer_list<double>::iterator p = il.begin(); p!=il.end(); p++) {
}
for(auto p = il.begin(); p!=il.end(); p++) {
}
decltype
将变量的类型声明为表达式指定的类型
decltype(x) y;//让y的类型与x相同,其中x是一个表达式。
double x;
int n;
decltype(x*n) q; //q 是double类型
decltype(&x) q; //pd 是&x,double*型
通常用在模板里
template<typename T, typename U>
void ef(T t, U u) {
decltype (T*U) tu;
}
返回类型后置
新增函数声明语法,在函数名和参数列表后面(而不是前面)指定返回类型。
double f1(double, int);
auto f2(double, int) -> double;
模板别名:using =
using itType = std::vector<std::string>::iterator;
可以用于模板部分具体化:
template<typename T>
using arr = srd::array<T, 12>;
nullptr: 空指针
基于范围的for循环:
for(double x : prices) {
}
for (auto x : prices) {
}
如果要修改容器中的每个元素,可以用引用类型
std:vector<int> vi(6);
for (auto &x : vi) {
x = std::rand();
}
右值引用
左值引用:可以出现在赋值语句的左边,int & rn = n;
右值引用:使用&&表示,可以关联到右值,即可以出现在赋值表达式的右边,但不能对其应用地址运算符的值。
int x = 10;
int y = 23;
int && r1 = 13;
int && r2 = x + y;
r2 关联到的是当时x+y计算的结果,即r2关联的是23,即使以后修改了x或者y,也不会影响到r2.
将右值关联到右值引用,会导致该右值存储到特定的位置,且可以获取到该位置的地址。也就是虽然不能用于&13,但是可以用&r2。
移动语义和右值引用
std::move() 可以强制将左值移动为右值
Useless one(10, ‘x’);
Useless four = std::move(one);
one是一个左值,但通过std::move(one) 变成右值,将调用移动构造函数。
Useless & Useless::operator=(Useless && f) {
}
默认方法和禁用方法
default
如果提供了某个构造函数,编译器将不会自动自动默认的构造函数。例如提供可一个构造函数,编译器将不会再提供默认构造函数,复制构造函数,移动构造函数等。
如果想用编译器提供的构造函数,可以使用default关键字
class Someclass {
public:
Someclass(Someclass &&);
Someclass() = default;
Someclass(const Someclass &) = default;
Someclass & operator = (const Someclass &) = default;
}
编译器将创建在没有提供默认构造函数的情况下,自动提供构造函数。
delete
用于禁止编译器使用特定的方法,例如禁止复制对象,可禁用复制构造函数和复制赋值运算符。
把方法放到private,能达到相同的目的。
class Someclass {
public:
Someclass(Someclass &&);
Someclass() = default;
Someclass(const Someclass &) = delete; //禁用复制构造函数
Someclass & operator = (const Someclass &) = delete;
}
管理虚方法:override 和 final
override
如果子类重写了父类函数,但是特征标不一样,将隐藏父类方法。
例如:
class Action {
int a
public:
Action(int i = 0): a(i) {}
int val() const {return a;}
virtual void f(char ch) const {std::const << val() << ch << "\n";}
}
class Bingo : public Action {
int a
public:
Bingo (int i = 0): Action(i) {}
virtual void f(char * ch) const {std::const << val() << ch << "\n";}
}
由于子类Bingo定义f(char * ch) 而不是f(char ch), 将对Bingo对象隐藏f(char ch);将导致程序不能使用下边代码:
Bingo b(10);
b.f('@'); //不被允许,因为父类方法f(char) 被隐藏
说明符override指出,程序将覆盖一个虚函数,如果声明与父类方法不匹配,编译器将报错。
virtual void f(char * ch) const override {
std::cout << val() << ch << "!\n";
}
编译器将报错
final:
禁止编译器覆盖特定的虚方法。
virtual void f(char ch) const final {
}
将禁止Action 的派生类重新定义函数f()
Lambad函数(匿名函数)
[&count] (int x) {
count + = (x % 13 == 0);
}
[] (int x) {return (x % 13 == 0);}
[]相当于函数名,没有声明返回类型,编译器会像decltyp一样,自动推断返回类型
count3 = std::count_if(numbers.begin(), numbers.end(),
[] (int x) {return x % 3 == 0;});
lambda可以访问作用域内的任何动态变量,要捕获要使用的变量,可以将器名称放在中括号内,如果只指定了变量名[z], 将按值访问变量;如果在名称前加上&,[&count] 将按引用访问变量。
也可以多个[ted, &ted]