前言
一、列表的初始化
1.C++11扩大了{}初始化列表的使用范围,不仅可以对数组进行初始化,也可以用于所有的内置类型和用户自定义类型(使用初始化列表时=可加可不加)。
#include<iostream>
#include<vector>
using namespace std;
template<class Type>
class Array
{
public:
Array() :ar(nullptr), capacity(0), size(0)
{}
Array(int sz)
{
capacity = sz;
ar = new Type[capacity];
size = 0;
}
//多个对象想要支持列表初始化,需给该类(模板类)添加一个带有initializer_list类型参数的构造函数。
//注意:initializer_list是系统自定义的类模板,该类模板中主要有三个方法:begin()、end()迭代器,获取中间元素个数的方法size()。
Array(initializer_list<Type> lt) :size(0)
{
capacity = lt.size();
ar = new Type[capacity];
auto it = lt.begin();
while (it != lt.end())
{
ar[size++] = *it++;
}
}
private:
Type* ar;
size_t capacity;
size_t size;
};
int main()
{
//内置类型变量
int a{ 0 };
int a1 = { 0 };
//数组
int array1[] = { 1,2,3,4 };
int array2[]{ 1,2,3,4 };
int array3[2]{ 1,2 };
//动态数组
int* array4 = new int[4]{ 1,2,3,4 };
//容器
vector<int> v{ 1,2,3,4 };
//自定义类型
Array<int> A1{ 3 };
Array<int> A2 = { 1,2,3,4,5 };
return 0;
}
二、变量类型推导
1.在不清楚变量类型或者类型过于复杂时可以使用auto进行类型推导
using namespace std;
int main()
{
int a = 0;
auto b = a;
cout << typeid(b).name() << endl;
vector<int> v{ 1,2,3,4 };
auto it = v.begin();
cout << typeid(it).name() << endl;
}
三、默认成员函数控制
C++11对于空类编译器会默认生成的函数:构造函数、析构函数、拷贝构造函数、赋值运算符重载函数、&和const&的重载、移动构造、移动拷贝构造等函数。
1.显示缺省函数:如果自己定义了某函数又想让编译器生成该函数的默认版本,在默认函数定于或声明时加上=default。
2.删除默认函数:如果要禁止编译器生成某一函数的默认函数,可以在该函数的声明后面加上=delete。
class ex
{
public:
ex(int n):_m(n)
{}
//显示缺省函数,让编译器生成默认构造函数
ex() = default;
//禁止编译器生成默认的拷贝构造函数
ex(const ex&) = delete;
private:
int _m;
};
四、左值与右值
1.左值与右值的主要区别:
(1)左值可以被修改右值不可以
(2)左值可以取地址右值不可以
(3)普通引用只能引用左值不能引用右值(const引用可以引用左值也可以引用右值)
2.右值引用要想引用左值,必须通过std::move()函数将左值转换为右值。
3.移动语义:将一个对象的资源传递给另一个对象,不需要新开辟空间。
#include<iostream>
using namespace std;
class String
{
public:
String(const char* str=" ")
{
cout << "Create:" << this << endl;
_str = new char[strlen(str) + 1];
strcpy_s(_str, strlen(str) + 1, str);
}
//移动构造函数
String(String &&s)
{
cout<<"Move Create:<<this<<endl;
//不需要创建新的空间,直接将空间传递
_str = s._str;
s._str = nullptr;
}
String(const String& s) :_str(new char[strlen(s._str) + 1])
{
cout << "Copy Create:" << this << endl;
strcpy_s(_str, strlen(s._str) + 1, s._str);
}
String operator+(const String& s)
{
char* tmp = new char[strlen(_str) + strlen(s._str) + 1];
strcpy_s(tmp, strlen(_str) + 1, _str);
strcpy_s(tmp + strlen(_str), strlen(s._str) + 1, s._str);
String res(tmp);
return res;
}
~String()
{
cout << "Free:" <<this<< endl;
if(_str)
delete[] _str;
_str = nullptr;
}
private:
char* _str;
};
int main()
{
String s1("hello");
String s2("world");
String s3(s1 + s2); //hello world
return 0;
}
(1)有移动构造函数的运行结果
(2)没有移动构造函数的运行结果
4.完美转发
函数模板在向其他函数传递自身形参时,相应实参为左值就转发为左值,相应实参为右值就转发为右值。要利用forward函数进行实现。
#include<iostream>
using namespace std;
void Fun(int& x)
{
cout << "lvalue" << endl;
}
void Fun(int&& x)
{
cout << "rvalue" << endl;
}
void Fun(const int& x)
{
cout << "const lvalue" << endl;
}
void Fun(const int&& x)
{
cout << "const rvalue" << endl;
}
template<typename Type>
void PF(Type&& t)
{
//利用forward函数实现完美转发
Fun(forward<Type>(t));
}
void main()
{
PF(10);
int a = 10;
PF(a);
const int& x=10;
PF(x);
const int&& y = 10;
PF(move(y));
}
运行结果
五、lambda表达式
1.形式:[捕捉列表](参数列表)->返回值类型{函数体}
2.lambda相当于一种匿名函数,默认情况下是一个const函数
3.捕获列表说明
(1)[var]:以传值方式传递捕获的该变量,不可以在lambda函数体内对该值进行修改。
(2)[=]:以传值方式传递捕获的lambda函数体所在语句块中的所有变量。
(3)[&val]:以引用方式传递捕获的该变量,可以在lambda函数体内对该变量进行修改,但出了lambda函数体后,该变量并不会被改变。
(4)[&]以引用方式传递捕获的lambda函数体所在语句块中的所有变量。
(5)[this]:以传值方式传递捕获的this指针
#include<iostream>
using namespace std;
int main()
{
int x = 1;
//最简单的lambda表达式
[] {};
//调用方法一
auto fun = []()->void
{
cout << "调用方法一" << endl;
};
fun();
//调用方法二
[]()->void
{
cout << "调用方法二" << endl;
}();
int res1 = [](int a, int b)->int
{
return a + b;
}(1, 2);
cout << "res1 = " << res1 << endl;
//传值方式传递捕捉的变量
int res2 = [x]()->int
{
return x;
}();
cout << "res2 = " << res2 << endl;
int res3 = [=]()->int
{
return x;
}();
cout << "res3 = " << res3 << endl;
//引用方式传递捕捉的值
int res4 = [&x]()->int
{
x = 10;
return x;
}();
cout << "res4 = " << res4 << endl;
int res5 = [&]()->int
{
x = 10;
return x;
}();
cout << "res5 = " << res5 << endl;
return 0;
}
运行结果
4.仿函数与lambda表达式
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Test
{
public:
Test(int data = 0) :m_data(data)
{}
public:
int m_data;
};
struct my_greater
{
bool operator()(const Test& t1, const Test& t2)const
{
return t1.m_data > t2.m_data;
}
};
void main()
{
vector<Test> tv = { 4, 1, 8, 5, 3, 7, 0, 9, 2, 6 };
//my_greater()仿函数(在类中重载operator()运算符)实现从大到小排序
sort(tv.begin(), tv.end(), my_greater());
//lambda表达式实现从大到小排序
sort(tv.begin(), tv.end(), [](const Test& t1, const Test& t2)->bool {return t1.m_data > t2.m_data; });
}