C++11中的初始化列表,右值引入,lambda表达式等

一、C++11的介绍:

相较于C++98/03,C++11则带来了数量可观的变化,其中包含了约140个新特性,以及对C++03标准中约600个缺陷的修正,这使得C++11更像是从C++98/03中孕育出的一种新语言。相比较而言,C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大,而且能提升程序员的开发效率。

二、C++11中的主要知识概念:
(一)、初始化列表:
  1. 概念:C++98允许{}对数组元素进行数值初始化,C++11扩大了{}初始化范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,可添加等号(=),也可不添加。
  2. 内置类型列表初始化:
#include<iostream>
#include<set>
using namespace std;

int main()
{
	//内置类型
	int arr[] = { 1, 2, 3, 4, 5 };//c++98
	int arr1[]{1, 2, 3, 4, 5};//c++11
	int x{ 1 };//c++11
	int y{ 1 + 2 };//c++11
	//动态数组C++98没有
	int* arr2 = new int[6]{ 1, 2, 3, 4, 5, 6 };
	//容器
	set<int> s1{ 1, 2, 3, 4, 5 };
	return 0;
}
  1. 自定义类型初始化:(一个对象的初始化列表)
class Point
{
public:
	Point(int x = 0, int y = 0): _x(x), _y(y)
	{}
private:
	int _x;
	int _y;
};
int main()
{
	Pointer p{ 1, 2 };
	return 0;
}
(二)、变量类型推导:
  1. auto:
  • 使用前提:必须要对auto声明的类型进行初始化,否则编译器无法推导出auto的实际类型。
int main()
{
	int a = 10;
	//必须知道a的类型,才能auto出c的类型
	auto c = a;
	c = 12;
	cout << c << endl;
	return 0;
}
  1. typeid:只能查看类型不能用其结果定义类型。
  • C++98中确实已经支持RTTI:
    (1)typeid:只能查看类型不能用其结果类定义类型
    (2)dynamic_cast:只能应用于含有虚函数的继承体系中(dynamic_cast解析
  1. decltype:decltype是根据表达式的实际类型推演出定义变量时所用的类型。
  • 推演表达式类型作为变量的定义类型
int main()
{
	int a = 1;
	int c = 2;

	decltype(a + c) d = 10;
	cout << typeid(d).name() << endl;//int

	return 0;
}
  • 推演函数返回值的类型
#include<iostream>
using namespace std;

void* fun(size_t size)
{
	return malloc(size);
}

int main()
{
	//函数的类型
	cout << typeid(decltype(fun)).name() << endl;
	//函数返回值类型
	cout << typeid(decltype(fun(0))).name() << endl;

	return 0;
}
(三)、C++11中 for(auto& e : arr):
  • 主要用于遍历数组或容器:
using namespace std;

int main()
{
	//数组
	int arr[] {1, 2, 3, 4, 5};
	for (auto& e : arr)
		cout << e << " ";
	cout << endl;
	//容器
	vector<int> vt{ 1, 2, 3, 4, 5, 6 };

	for (auto& e : vt)
		cout << e << " ";
	cout << endl;

	return 0;
}

(四)、final与override:
  1. final:终止继承,在类后加表示类不能被继承;在虚函数后加上,则表示该函数不能再被重写。
  2. override:检验子类虚函数是否重写父类的方法,如果没有则编译出错。
(五)、默认成员函数控制:
  1. default–显示缺省函数
  2. delete–删除默认函数
#include<iostream>
using namespace std;

class A
{
public:
	A() = default;
	//系统默认生成A()
	A(int a) : _a(a)
	{}
	// 禁止编译器生成默认的拷贝构造函数以及赋值运算符重载
	A(const A&) = delete;
	A& operator=(const A&) = delete;
private:
	int _a;
};
int main()
{
	A a1(10);
	//A a2(a1);//错误
	A a;
	return 0;
}
(六)、右值引用:
  1. 左值与右值:
    左值:一般认为等号右边的或者能取地址称为左值;
    右值:一般认为放在=右边的,或者不能取地址的称为右值。
    (1)普通类型的变量,因为有名字,可以取地址,都认为是左值.
    (2)const修饰的常量,不可修改,只读类型的,理论应该按照右值对待,但因为其可以取地址(如果只是const类型常量的定义,编译器不给其开辟空间,如果对该常量取地址时,编译器才为其开辟空间),C++11认为其是左值。
    (3)如果表达式的运行结果是一个临时变量或者对象,认为是右值。
    (4)如果表达式运行结果或单个变量是一个引用则认为是左值.

注意

  • 不能简单地通过能否放在=左侧右侧或者取地址来判断左值或者右值,要根据表达式结果或变量的性质判断.
  • 能得到引用的表达式一定能够作为引用,否则就用常引用。
  1. 左值引用

(1).const引用既能引用左值,也能引用右值:

int main()
{
	int a = 10;
	int& pa = a;
	const int& pc = a;
	a = 20;
	cout << pa << endl;
	//int& pb = 20;错误;
	const int& pb = 20;//
	cout << pb << endl;

	const int a1 = 10;
	// int& pa1 = a1; //由于a1 为 const int 类型 所以左值引用会出现错误
	// pa1 = 20;
	cout << a1<< endl;
	//cout << pa1 << endl;
	return 0;
}
  1. 右值引用
    C++11中:只能引用右值,一般情况不能直接引用左值。
int main()
{
	// 10纯右值,本来只是一个符号,没有具体的空间,
	// 右值引用变量r1在定义过程中,编译器产生了一个临时变量,r1实际引用的是临时变量
	int&& r1 = 10;
	r1 = 100;
	int a = 10;
	//int&& r2 = a; // 编译失败:右值引用不能引用左值
	return 0;
}
  1. 移动语义:将一个对象中资源移动到另一个对象中的方式。
  • 右值引用引用左值:
    当需要用右值引用引用一个左值时,可以通过move函数将左值转化为右值。C++11中,std::move()函数位于 头文件中,该函数名字具有迷惑性,它并不搬移任何东西,唯一的功能就是将一个左值强制转化为右值引用,然后实现移动语义。
    注意:
    (1). 被转化的左值,其生命周期并没有随着左值的转化而改变,即std::move转化的左值变量lvalue不会被销毁。
    (2). STL中也有另一个move函数,就是将一个范围中的元素搬移到另一个位置。
int main()
{
	//s1此时无效
	string s1("string");
	string s2(move(s1));
	string s3(s2);

	for (auto& e : s1)
		cout << e << " ";
	cout << endl;//空的
	return 0;
}
Person(Person&& p)
: _name(move(p._name))
, _sex(move(p._sex))
, _age(p._age)
{}
  1. 完美转发:
    完美转发是指在函数模板中,完全依照模板的参数的类型,将参数传递给函数模板中调用的另外一个函数。
void Fun(int &x){cout << "lvalue ref" << endl;}
void Fun(int &&x){cout << "rvalue ref" << endl;}
void Fun(const int &x){cout << "const lvalue ref" << endl;}
void Fun(const int &&x){cout << "const rvalue ref" << endl;}
template<typename T>
void PerfectForward(T &&t){Fun(std::forward<T>(t));}
int main()
{
	PerfectForward(10); // rvalue ref
	int a;
	PerfectForward(a); // lvalue ref
	PerfectForward(std::move(a)); // rvalue ref
	const int b = 8;
	PerfectForward(b); // const lvalue ref
	PerfectForward(std::move(b)); // const rvalue ref
	return 0;
}
  1. 右值引用的作用
    (1). 实现移动语义(移动构造与移动赋值)
    (2). 给中间临时变量取别名
int main()
{
	string s1("hello");
	string s2(" world");
	string s3 = s1 + s2; // s3是用s1和s2拼接完成之后的结果拷贝构造的新对象
	stirng&& s4 = s1 + s2; // s4就是s1和s2拼接完成之后结果的别名
	return 0;
}
(七)、lambda表达式:相当于一个匿名函数
  1. lambda表达式基本语法:
  •   auto fun = [=, &b](int c)->int{return b += a+ c; };
      	[] : 扑捉列表;
      	() : 参数列表;
      	-> int: 返回值类型;
      	{} : 函数体.
    

注意: 在lambda函数定义中**,参数列表和返回值类型都是可选部分**,而捕捉列表和函数体可以为空。因此C++11中最简单的lambda函数为:[]{}; 该lambda函数不能做任何事情。
捕获列表说明
捕捉列表描述了上下文中那些数据可以被lambda使用,以及使用的方式传值还是传引用。

  •   [var]:表示值传递方式捕捉变量var
      [=]:表示值传递方式捕获所有父作用域中的变量(包括this)
      [&var]:表示引用传递捕捉变量var
      [&]:表示引用传递捕捉所有父作用域中的变量(包括this)
      [this]:表示值传递方式捕捉当前的this指针
    
// lambda表达式:
int main()
{
	//最简单的lambda表达式
	auto f1 = []{};

	int a = 3;
	int b = 4;
	//省略参数列表
	[=]{return a + b; };

	//省略返回值类型,
	auto f2 = [=,&b](int c){return b = a + c; };

	f2(10);
	cout << f2(10) << endl;

	auto fun2 = [=, &b](int c)->int{return b += a + c; };
	cout << fun2(10) << endl;

	return 0;
}
  1. 函数对象与lambda表达式:
class Rate
{
public:
	Rate(double rate) : _rate(rate)
	{}
	double operator()(double money, int year)
	{
		return money * _rate * year;
	}
private:
	double _rate;
};
int main()
{
	// 函数对象
	double rate = 0.49;
	Rate r1(rate);
	r1(10000, 2);
	// lamber
	auto r2 = [=](double monty, int year)->double{return monty*rate*year; };
	r2(10000, 2);
	return 0;
}

实际在底层编译器对于lambda表达式的处理方式,完全就是按照函数对象的方式处理的,即:如果定义了一个lambda表达式,编译器会自动生成一个类,在该类中重载了operator()

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值