自学 C++ day11 C++11特性

本文详细介绍了C++11的一些重要新特性,包括内置类型和自定义类型的列表初始化、decltype用于类型推导的功能、显示缺省函数和删除默认函数的用法,以及左值和右值的概念。同时,还探讨了右值引用在移动语义中的应用,以及lambda表达式的使用。通过对这些特性的理解,开发者可以更好地利用C++11提高代码的效率和可读性。
摘要由CSDN通过智能技术生成
// C++ 11 新特性:

// 1、 内置类型列表初始化
// 列表初始化可以在{}之前使用=,其效果与不使用=没有区别;
#if 0
int main() {
	//内置类型变量
	int x1 = { 10 };
	int x2{ 10 };
	int x3 = 1 + 2;
	int x4 = { 2 + 3 };
	int x5{ 3 + 4 };

	// 内置类型数组
	int arr[5]{ 1,2,3,4,5 };
	int arr2[]{ 1,1,2,4 };

	// 动态数组
	int* arr = new int[5]{ 1,2,3,4,5 };

	// 标准容器
	vector<int> v{ 1,2,3,4,5 };
	map<int, int> m{ {1,2},{2,3},{3,4} };
	return 0;
}
#endif 


// 自定义类型的列表初始化
#if 0
class Point {
public:
	Point(int x = 0, int y = 0):_x(x),_y(y){}

private:
	int _x;
	int _y;
};

// 单个对象的初始化列表
int main() {
	Point p{ 1,2 };
	return 0;
}

// 多个对象的初始化列表
// 多个对象想要只吃列表初始化,需要该类(模板类)带友initializer_list类型参数的构造函数即可
// 注意: initializer_list 是系统自定义的类模板,该类模板主要友三个方法begin(),end()迭代器以及获取区间中元素个数的方法size()

#include <initializer_list> 

template<class T> 
class Vector {
public:
	Vector(initializer_list<T> l) :_capacity(l.size()), _size(0) {
		_array = new T[_capacity];
		for (auto e : l) {
			_array[_size++] = e;
		}
	}
private:
	T* _array;
	size_t _capacity;
	size_t _size;
};
#endif 


// decltype : 类型推导

// typeid 只能查看类型不能用其结果类定义类型;
// dynamic_cast 只能应用于含有虚函数的继承体系中;

// decltype 是根据表达式的实际类型推演出变量所用的类型。
// 比如 1. 推导表达式类型作为变量的定义类型

#if 0
void declt() {
	int a = 1;
	int b = 2;

	// 用decltyte推演a+b的实际类型,作为c的类型
	decltype(a + b) c;
	cout << typeid(c).name() << endl;
	return 0;
}
#endif 


// 推演函数返回值的类型
#if 0
#include <iostream> 
#include <cstring>
#include <string>
using std::cout;
using std::endl;
using std::string;
void* GetMemory(size_t size) {
	return malloc(size);
}

int main() {
	// 没有带参数,推导函数的类型
	cout << typeid(decltype(GetMemory)).name() << endl;

	// 如果带友参数列表推导的是函数返回值的类型,注意这里只做推演,不会执行函数
	string name = typeid(decltype(GetMemory(8))).name();
	cout << name << endl;
	return 0;
}
#endif 


// 显示缺省函数
// 在C++ 11 中,可以在默认定义或者声明上加上=default, 从而显示的指示编译器生成该函数的默认版本; 用=default 修饰的函数称为显示缺省函数

// 删除默认函数
// 如果想要限制某些默认函数的生成,在C++98中,是该函数设置成private,并且不给定义,这样只要其他人想要调用就会报错。 
// 在C++11 中更简单,只需要在该函数的声明上加上=delete即可,该语法指示编译器不生成对应函数的默认版本,称=delete 修饰的函数为删除函数.



#if 0

// 左值与右值:
// 左值与右值是C语言中的概念,但在C标准中没有给出严格的区分方式,一般认为: 客户以放在 = 左边的或者能够 取地址的称为左值,
// 只能放在 = 右边的,或者不能取地址的称为右值;

#include <iostream> 
using std::cout;
using std::endl;

int g_a = 10;

int& GetG_A() {
	return g_a;
}

int main() {
	int a = 10;
	int b = 20;

	// a 和 b 都是左值,b既可以在 =的左侧 也可以在 =的右侧,
	// 说明:左值既可以放在 = 的左侧,也可以放在 = 的右侧;

	a = b;
	b = a;

	const int c = 30;
	// c = a; 编译失败,c为常量,只读不允许被修改

	// 因为可以对c取地址,因此c严格来说不算是左值
	cout << &c << endl;

	// b +1 = 20 编译失败:因为b+1的结果是一个临时变量,没有具体名称,也不能取地址,因此为右值

	GetG_A() = 100;
	return 0;
}

关于左值与右值的区分:
1. 普通类型变量,因为有名字,可以取地址,都认为是左值;
2. const 修饰的常量,不可以修改,只读类型的,理论应该按照右值来对待,但是应为器可以取地址(如果只是 const 类型常量的定义
编译器不给其开辟空间,如果对该常量取地址是,编译器才为其开辟空间),C++11默认其为左值。
3. 如果表达式的运行结果是一个临时变量或者对象,认为是右值。
4. 如果表达式运行结果或单个变量是一个引用则认为是左值。


引用与右值的比较:

普通引用只能引用左值,不能饮用右值,const 引用既可以引用左值,也可以引用右值。
int val() {
	// 普通引用只能引用左值,不能引用右值
	int a = 10;
	int& ra1 = a;

	// int& ra2 = 10; 编译错误,因为10是右值

	const int& ra3 = 10;
	const int& ra4 = a; 
	return 0;
}


C++ 中的右值引用,只能引用右值,一般情况不能引用左值;

void test() {
	// 10 纯右值,本来只是一个符号,没有具体空间,
	// 右值引用r1在定义过程中,编译器产生了一个临时变量,r1实际引用的是临时变量;
	int&& r1 = 10;
	r1 = 100;

	int a = 10;
	// int&& r2 = a; 编译失败、右值引用不能引用左值;
}



移动语义: 将一个对象中资源移动到另外一个对象中去。

当需要用右值引用引用一个左值是时,可以通过std::move()函数将左值转化为右值。
它并不搬移任何东西,唯一的功能就是将一个左值强制转换为右值引用,让后实现移动语义。


完美转发是指在函数模板中,完全按照模板的参数的类型,将参数传递给函数模板中调用的另外一个函数。(完美的转发的接受转发的函数是不会察觉到有中间商的)

#endif 




// lambda 表达式
// [捕捉列表](参数列表)mutable->返回值类型{statement} 
// [capture-list] : 捕捉列表,该列表出现在lambda函数的开始位置,编译器根据[]来判断接下来的代码是否为lambda函数,
// 捕捉列表能够捕捉上下文中变量提供给lambda函数使用。
// (parameters): 参数列表。与普通函数的参数列表一直,如果不需要可以连同() 一起省略。
// mutable : 默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。使用该修饰符时,参数列表不可省略。
// ->return-type : 返回值类型。用追踪返回类型形式声明函数的返回值类型,没有返回值时此部分可省略。返回值类能被推导也可以省略。
// {statement} :函数体。 在函数体内,可以使用其参数外,还可以使用捕获到的变量。

// 注意: lambda 函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为空。

// [var] : 表示值传递的方式捕捉变量的var
// [=] : 表示值传递方式补货所有父作用域中的变量(包括this)。
// [&var] : 表示引用传递捕捉变量var
// [&] : 表示引用传递捕捉所有父作用域的变量(包括this)。
// [this]: 表示值传递的方式捕捉当前this指针。
// a. 父作用域是指包含lambda函数的语句块。
// b. 语法上捕捉列表可以由多个捕捉项组成,并以 , 分割。
// c. 捕捉列表不允许变量重复传递,否则就会导致编译错误。
// d. 在块作用域以外的lambda函数捕捉列表必须为空。
// e. 在块作用域中的lambda函数仅能捕捉父作用域中的局部变量,捕捉任何非此作用域或者非局部变量都会导致编译报错。
// f. lambda表达式之间不能相互赋值,即使看起来类型相同。


// 函数对象:又称仿函数,既可以像函数一样使用的对象,就是在类中重载了operator()运算符的类对象。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值