栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

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

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

// 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 v{ 1,2,3,4,5 };
	map 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  

template 
class Vector {
public:
	Vector(initializer_list 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  
#include 
#include 
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  
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()运算符的类对象。


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1033693.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号