感慨时间过的好快,C++ 11出来都5年了,现在才开始学习,但为时也不晚;
主要是网上及身边的朋友大肆宣扬C++ 11的某些优化,弄得别人心里痒痒的,所以就花了3天学习了点基本知识,相对于整个C++ 11的新增来说就是九牛一毛;
先上一张C++ 11的图:
1.推导关键词 auto & decltype;
详解:http://blog.youkuaiyun.com/zhlstud/article/details/71308270
2.Lambda的使用;
详解:http://blog.youkuaiyun.com/zhlstud/article/details/71308205
3.统一初始化的语法;
详解:http://blog.youkuaiyun.com/zhlstud/article/details/71308291
4.Delete和Default函数
1.简介
我们知道C++的编译器在你没有定义某些成员函数的时候会给你的类自动生成这些函数,比如,构造函数,拷贝构造,析构函数,赋值函数。有些时候,我们不想要这些函数,比如,构造函数,因为我们想做实现单例模式。传统的做法是将其声明成private类型。
在新的C++中引入了两个指示符,delete意为告诉编译器不自动产生这个函数,default告诉编译器产生一个默认的
2.例子
Default:
structA
{
A()=default; //C++11
virtual~A()=default; //C++11
};
Delete:
structNoCopy
{
NoCopy & operator =( constNoCopy & ) = delete;
NoCopy ( constNoCopy & ) = delete;
};
NoCopy a;
NoCopy b(a); //compilation error, copy ctor is deleted
解析:default看起来貌似毫无用处,本来就会默认构造,但如果有定义构造,编译器就不会默认构造,这时候你用到default就是让默认构造和自定义构造共存;如下:
structSomeType
{
SomeType() = default; // 使用编译器生成的默认构造函数
SomeType(OtherType value);
};
3.Delete两个有用点:
a.让对象只能生成在栈内存上;
structNonNewable {
void*operator new(std::size_t) = delete;
};
b.阻止函数的形参类型的调用;(若尝试以 double 的形参调用 f(),将会引发编译期错误, 编译器不会自动将 double 形参转型为 int 再调用f())
voidf(inti);
voidf(double) = delete;
5.nullptr 和委托构造函数
1.题外话
C/C++的NULL宏是个被有很多潜在BUG的宏。因为有的库把其定义成整数0,有的定义成 (void*)0。在C的时代还好。但是在C++的时代,这就会引发很多问题
2.nullptr 是强类型的。
voidf(int); //#1
voidf(char*);//#2
//C++03
f(0); //二义性
//C++11
f(nullptr) //无二义性,调用f(char*)
3.所有和指针相关的地方都用nullptr,包括函数指针和成员指针;
const char *pc=str.c_str(); //data pointers
if (pc!=nullptr)
cout<<pc<<endl;
int (A::*pmf)()=nullptr; //指向成员函数的指针
void (*pmf)()=nullptr; //指向函数的指针
--------------委托构造函数--------------
1.题外话
在以前的C++中,构造函数之间不能互相调用,所以,我们在写这些相似的构造函数里,我们会把相同的代码放到一个私有的成员函数中
2.定义:
C++11 中构造函数可以调用同一个类的另一个构造函数:
5.例子
class M //C++11 delegating constructors
{
int x, y;
char *p;
public:
M(int v) : x(v), y(0), p(new char [MAX]) {} //#1 target
M(): M(0) {cout<<"delegating ctor"<<end;} //#2 delegating
解析:#2 就是所谓的委托构造函数,调用了真正的构造函数 #1。
6.右值引用和move语意
1.目的
a.消除两个对象交互时不必要的对象拷贝,节省运算存储资源,提高效率;
b.能够更简洁明确的定义泛型函数;
2.左值的声明符号为“&”,为了和左值区分,右值声明符为“&&”;
例子:
void process_value(int& i) {
std::cout << "LValue processed: " << i << std::endl;
}
void process_value(int&& i) {
std::cout << "RValue processed: " << i << std::endl;
}
int main() {
int a = 0;
process_value(a); //输出Lvalue 0;
process_value(1); //输出Rvalue 1
}
3.但是如果临时对象通过一个接受右值的函数传递给另一个函数时,就会变成左值,因为这个临时对象在传递过程中,变成了命名对象。
void process_value(int& i) {
std::cout << "LValue processed: " << i << std::endl;
}
void process_value(int&& i) {
std::cout << "RValue processed: " << i << std::endl;
}
void forward_value(int&& i) {
process_value(i);
}
int main() {
int a = 0;
process_value(a); //Lvalue 0
process_value(1); //Rvalue 1
forward_value(2); //Lvalue 2
}
7.Override和final
1.解释;
Override:表示派生类应当重写这个基类中的这个虚函数;
Final: 表示派生类不应当重写这个虚函数;
//Overrride例子
classB
{
public:
virtualvoidf(int){std::cout<<"B::f"<<std::endl;}
};
classD:publicB
{
public:
virtualvoidf(int)override{std::cout<<"D::f"<<std::endl;}
};
//Final例子
classB
{
public:
virtualvoidf(int){std::cout<<"B::f"<<std::endl;}
};
classD:publicB
{
public:
virtualvoidf(int)overridefinal{std::cout<<"D::f"<<std::endl;}
};
classF:publicD
{
public:
virtualvoidf(int)override{std::cout<<"F::f"<<std::endl;}
};
报错,在类D中就已经声明不再重写这个虚函数
8.区间迭代
1.意义:所有语言都有一种对一个区间写for循环的便捷方式;
例子:
vector<int> vec{ 3, 5, 6, 10, 23 };
for (auto i:vec)
{
cout << i << endl;
}