目录
=default, = delete 配合构造函数和拷贝赋值 一起使用
Alias Template(template typedef)
=default, = delete 配合构造函数和拷贝赋值 一起使用
对于一个空的class c++编译器处理之后就会不在是一个空的class 因为编译器会为这个class添加
- copy ctor
- copy assignment operator(=)
- dtor
就是Big Three 如果你没有声明ctor 编译器会为你声明一个default ctor且都是public inline的
目的:是为了在这些函数中添加一些默认的行为,比如在ctor中调用父类的ctor或者dtor中调用父类的dtor
class Empty{}; ==>
class Empty{
public:
// Big Three
Empty() {...}
~Empty() {...}
Empty(const Empty& e) {...} // 默认行为是一个位一位的拷贝
Empty& operator-()(const Empty& e){...}
}
如果一个类中包含指针对象 就需要自己实现 Big Three
Alias Template(template typedef)
template<typename T>
using Vec = std::vector<T, MyAlloc<T>>;//给一个化名
Vec<int> coll;
//typedef 做不到,typedef不能接受参数
//define 也不行
//#define Vec<T> template<typename T> std::vector<T,MyAlloc<T>>;
//Vec<int> coll;
Type Alias别名
// typedef void(*func)(int, int);
// func是一个类型 是一个函数指针
// 和typedef没有区别
using func = void(*)(int, int);
void example(int, int) {};
// 函数名就是一个函数指针
func fn = example;
using
一般的using关键子我们都是用来声明当前文件的命名空间,比如标准库的命名空间std-> using namespace std;
但在c++11中,它的用处还有几个 1:取代typedef ,2:让父类同名函数在子类中以重载方式使用.
// #1 using namespace std; using std::count;
// #2 声明成员函数 Base::test
// #3 用于alias
noexcept
在函数后面加上 noexcept 说明保证函数一定不会产生异常。该关键字告诉编译器,函数中不会发生异常,这有利于编译器对程序做更多的优化。如果在运行时,noexecpt函数向外抛出了异常(如果函数内部捕捉了异常并完成处理,这种情况不算抛出异常),程序会直接终止,调用std::terminate()函数,该函数内部会调用std::abort()终止程序。
void foo() noexcept;
void foo() noexcept(true); // 表明在上面条件下不会丢异常
override
在成员函数声明或定义中, override 确保该函数为虚函数并覆写来自基类的虚函数。
位置:函数调用运算符之后,函数体或纯虚函数标识 “= 0” 之前。
注意在派生类的成员函数中使用override时,如果基类中无此函数,或基类中的函数并不是虚函数,编译器会给出相关错误信息。
final
1、禁用继承:C++11中允许将类标记为final,方法时直接在类名称后面使用关键字final,如此,意味着继承该类会导致编译错误。
实例如下:
class Super final
{
//......
};
2、禁用重写: C++中还允许将方法标记为fianal,这意味着无法再子类中重写该方法。这时final关键字至于方法参数列表后面,如下
class Super
{
public:
Supe();
virtual void SomeMethod() final;
};
decltype
这个关键字的功能类似 typeof 返回对象的类型。它的作用是选择并返回操作数的数据类型,在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值。
总结:decltype和auto都可以用来推断类型,但是二者有几处明显的差异:1.auto忽略顶层const,decltype保留顶层const;2.对引用操作,auto推断出原有类型,decltype推断出引用;3.对解引用操作,auto推断出原有类型,decltype推断出引用;4.auto推断时会实际执行,decltype不会执行,只做分析。总之在使用中过程中和const、引用和指针结合时需要特别小心。
template<typename T1, typename T2>
auto add(T1 x, T2 y) -> decltype(x+y);
// error 因为编译到decltype(x+y)的时候 编译器不知道xy是什么东西
template<typename T1, typename T2>
decltype(x+y) add(T1 x, T2 y);
// auto cmp由编译器推导出类型
auto cmp = [](const Person& p1, const Person& p2) {
return p1.lastname() > p2.lastname();
}
// set需要传递一个函数类型 用decltype可以得出
std::set<Person, decltype(cmp)> coll(cmp);
参考:cnblogs.com/cauchy007/p/4966485.html
lambda
lambda没有构造和赋值函数。利用Lambda表达式,可以方便的定义和创建匿名函数。
auto l = [] {
strd::cout << "hello lambda" << std::endl;
}
l();
[...]中传递外部的变量
[&]传引用 mutable表示放在[]里面的变量可变 > > [=]表示默认接收外界的所有变量
右值引用
右值引用是新型的引用类型 帮助避免不必要的复制
当赋值的右手边是一个右值的时候 左手边的接受端可以偷右手边的资源而不需要执行allocation动作
Lvalue 可以出现在 = 左边 (左值表示变量的地址)
Rvalue 只能出现在 = 右边 (右值表示存储的真实的值)
类的临时对象是一个右值,临时变量一定被当成右值,因为临时对象创建之后 不会再被使用 所以直接把右值数据引用给别的变量,有时候一个左值在后面不会被用到,那么就可以使用move语义 把左值转成右值。
右值引用我的理解是编译器提供了一个接口 允许你进行赋值的时候直接使用右值的内存空间(其实就是将指针指向这块空间,当然在进行copy ctor和copy asgn的时候你需要自己实现操作,因为当你实现了右值引用的机制后编译器会自动调用你实现的函数),对于一些左值 但是如果在接下来的scope中你用不到了 在进行赋值的时候可以使用move语句将左值转变为右值,因为左值后面用不到了所以你可以把左值指向的内存的指针给删除(注意一定要删除指针,因为当这个左值的scope结束后,编译器会调用析构函数,如果没有删除指针,会把你move出去的这块内存给删除所以就造成了错误)