… 多个类型参数
在c++新特性中增加不定参数的设定
template<typename T>
void print(const T& arg)
{
}
template<typename T, typename ... Type>
void print(const T& first, const Type&... args)
{
cout << first << endl;
print(args...)
}
可以实现多个不同类型的参数
nullptr
使用 nullptr 代替 空指针。 因为c++支持函数重载。
void f(int);
void f(void *);
f(0);
f(NULL);
f(nullptr);
这时 f(NULL) 就出现了歧义,所以 尽量用 nullptr 代替 NULL
{} 初始化
初始化可以使用小括号,等于号,大括号,多种多样,现在一致使用 {} 大括号来进行数据得初始化,但是之前的初始化还是可以使用。
在变量的后面直接大括号表示赋初始值
int i{5};
string str{"wuyz"};
int arr[]{1,2,3,4};
initializer_list
当编译器遇到变量后面出现大括号,会先将大括号组装称 initializer_list<T>, 如果函数 有 initializer_list<T> 类型的参数,编译器会将其当作参数传递给函数,如果函数没有 initializer_list<T> ,则将其拆分,然后再去匹配相应的函数参数类型。
initializer_list<T> 不是内函数据,只是有指针指向相应的数据
initializer_list<T> 与 ... 的区别在于类型是否一致。 ... 可以接受类型不一致,但是 initializer_list<T> 参数要一致。
explicit
explicit 用来修饰构造函数表示,让编译器不要自动的转换。
1.例如当二元操作符进行运算时,编译器发现操作符的一个参数不符合,会调用转换的构造函数进行参数转换。 当这个不符合参数为第一个时,需要非成员函数操作符重载才能实现,当不符合参数为第二个时,成员函数操作符重载或是非成员函数操作符重载都可以。
explicit 在新特性中可以限定多个参数的隐式转换,因为 initializer_list<T>的出现导致
for and auto
for(auto it : { }){
cout << it << endl;
}
新特性的for循环,auto获取容器里面的元素(不是迭代器),
=default, =delete
=default 作用在函数后面表示使用编译器默认函数,
=delete 作用在函数后面表示删除默认函数。
当一个类不存在 构造函数,析构函数,赋值构造函数,赋值操作符,移动构造函数 时编译器会提供默的函数,这时可以使用 =default 告诉编译器使用默认函数,和 =delete告诉编译器删除默认函数
模板
这个不是新特性。
模板分为四种:类模板,函数模板,成员模板(类模板中的成员函数再次写称模板),模板模板(模板中的参数是一个模板)
using 取别名
使用using为容器或是模板取别名是可以在使用别名时传入类型参数,使用 typedef 定义的类型名是不可以传入参数的,即在typdedef时就需要知道模板类型参数。
using有三种用法,一种是导入命名空间,
using namespace std;
using std::cout;
第二种是 type alias,类型取别名
using funptr = void(*)(int, int);
typedef void(*funptr)(int, int);
第三种是 alias template,使用这种的作用是让编译器知道这个多类型模板,只算一个类型模板。
template<typename CharT>
using string = std::baisc_string<charT, std::char_traits<CahrT>>;
noexcept
在函数括号的后面加入 noexcept 保证该函数不抛出异常,特别是在移动构造函数和移动拷贝函数要加入noexcept ,这样子vector 容器才会取使用。
override
override 表示虚函数改写的意思,在派生类继承了基类时,想要改写基类的虚函数(子类虚函数必须和基类虚函数的函数名一致),当时不小心写错时,编译器会误会的觉得你重新定义一个虚函数,并没有替换基类的虚函数。想要编译器为你判断是否改写基类的虚函数,则在虚函数后面加 override ,当编译器发现基类没有此虚函数则会报错。
final
两种用法,
第一种用来修饰 类,表示该类式不能被继承的。
class A final {};
第二种用来修饰虚函数。表示虚函数不能被替换。
class A
{
virtual void func() final;
};
decltype()
decltype(expression) 可以根据表达式得到表达式返回的类型
decltype 可以用在三个地方
1.返回类型
template<typename T1, typename T2>
auto add(T1 a, T2 b) -> decltype(x+y);
2.根据对象确定类型
map<string, float> coll;
decltype(coll)::value_type elem;
3.用在 lambda 身上,推算出类型。
lambda
lambda可以作为一个参数或是局部对象,lambda的语法如下
[] { cout << endl; }
但是该lambda 没有名称,可以如下两种使用
1.直接调用
[] { cout << endl; } ();
2.产生一个对象,后续使用
auto l = [] { cout << endl; };
l();
完整语法 ,mutable ,throwspec , >retType 都是可选, … 表示参数
[…] (…) mutable throwspec ->retType { };
左值 与 右值
左值可以出现在 operator = 左右两边,
右值只能出现在 operator = 的右边
但是临时对象是右值,临时对象可以赋值。
当一个对象被引用传递时,编译器会分为右值引用还是左值引用,右值引用会优先匹配右值构造函数。
想要一个右值对象当作右值对象被引用,可以使用 move(obj); 会返回一个右值对象。