1.auto
在C++中,可以使用auto来根据变量初始化表达式类型推导变量的实际类型,简化程序的书写
auto i = 1;//i -> int
auto array = new auto(5);//array -> int *
auto s = "abc";
//c++ 03
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); it++) {
std::cout << *it << std::endl;
}
//c++ 11
for (auto it = vec.begin(); it != vec.end(); it++) {
std::cout << *it << std::endl;
}
注意:
auto 不能用于函数传参,因此下面的做法是无法通过编译的(考虑重载的问题,我们应该使用模板);
auto 不能用于推导数组类型
2.decltype
有时我们希望从表达式的类型推断出要定义的变量类型,但是不想用该表达式的值初始化变量(如果要初始化就用auto了)。
为了满足这一需求,C++11新标准引入了decltype类型说明符,它的作用是选择并返回操作数的数据类型,在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值。
int i;
double t;
struct A { double x; };
const A* a = new A();
decltype(a) x1; //x1 是 A*
decltype(i) x2; //x2 是 int
decltype(a -> x) x3; // x3 是 double
3.nullptr
空指针标识符nullptr是一个表示空指针的标识,他不是一个整数,这是与我们常用的NULL宏的区别。NULL只是一个定义为常整数0的宏,而nullptr是C++11的一个关键字,一个內建的标识符。
void fun(int a)
{
cout << "call function: [int]\n" << endl;
}
void fun(int *a)
{
cout << "call function: [int*]\n" << endl;
}
int main()
{
//C++11
fun(NULL); //call function: [int]
fun(nullptr); //call function: [int*]
int* p = NULL;
fun(p); //call function: [int*]
return 0;
}
4.lambda表达式
Lambda 表达式,实际上就是提供了一个类似匿名函数的特性,而匿名函数则是在需要一个函数,但是又不想费力去命名一个函数的情况下去使用的。
Lambda 表达式的基本语法如下:
[ caputrue ] ( params ) opt -> ret { body; };
- capture是捕获列表;
- params是参数表;(选填)
- opt是函数选项;可以填mutable,exception,attribute(选填)
mutable说明lambda表达式体内的代码可以修改被捕获的变量,并且可以访问被捕获的对象的non-const方法。
exception说明lambda表达式是否抛出异常以及何种异常。
attribute用来声明属性。 - ret是返回值类型(拖尾返回类型)。(选填)
- body是函数体。
class A
{
public:
int i_ = 0;
void func(int x,int y){
auto x1 = [] { return i_; }; //error,没有捕获外部变量
auto x2 = [=] { return i_ + x + y; }; //OK
auto x3 = [&] { return i_ + x + y; }; //OK
auto x4 = [this] { return i_; }; //OK
auto x5 = [this] { return i_ + x + y; }; //error,没有捕获x,y
auto x6 = [this, x, y] { return i_ + x + y; }; //OK
auto x7 = [this] { return i_++; }; //OK
};
int a=0 , b=1;
auto f1 = [] { return a; }; //error,没有捕获外部变量
auto f2 = [&] { return a++ }; //OK
auto f3 = [=] { return a; }; //OK
auto f4 = [=] {return a++; }; //error,a是以复制方式捕获的,无法修改
auto f5 = [a] { return a+b; }; //error,没有捕获变量b
auto f6 = [a, &b] { return a + (b++); }; //OK
auto f7 = [=, &b] { return a + (b++); }; //OK
注意:
[a,&b] 其中 a 以复制捕获而 b 以引用捕获。
[this] 以引用捕获当前对象( *this )
[&] 以引用捕获所有用于 lambda 体内的自动变量,并以引用捕获当前对象,若存在
[=] 以复制捕获所有用于 lambda 体内的自动变量,并以引用捕获当前对象,若存在
[] 不捕获,大部分情况下不捕获就可以了
5.for循环
C++11 引入了基于范围的迭代写法,我们拥有了能够写出像 Python 一样简洁的循环语句。
// & 启用了引用
for(auto &i : arr) {
std::cout << i << std::endl;
}
6.初始化列表
C++11扩大了用初始化列表的使用范围,让其适用于所有的内置类型和自定义类型,而且使用时,=可以不写
// 内置类型
int x1 = {10};
int x2{10}
// 数组
int arr1[5] {1,2,3,4,5}
int arr2[]{1,2,3,4,5};
// 标准容器
vector<int> v{1,2,3}
map<int,int> m{{1,1},{2,2}}
// 自定义类型
class Point
{
int x;
int y;
}
Power p{1,2};
7.override(更加安全直观)
class base {
public:
virtual void fun1(int);
virtual void fun2() const;
void fun3(int);
};
class son :public base {
//c++ 03 存在隐患
/*
void fun1(float); //不小心写错了参数,ok 编译通过,create a new func
void fun2(); //不小心少写了const,ok 编译通过,create a new func
void fun3();
*/
// but in c++ 11 更安全清晰
void fun1(float) override; //编译Error: no func to override
void fun2() override; //编译Error: no func to override
void fun3() override; //编译Error: no func to override
};
8.final
作用于类上,表示类不可被继承。
class Base final{
}
作用于虚函数上,表示该虚函数不可被重写。
class Base{
virtual void f() final;
}