10 C++11

news2024/11/24 15:32:22

10 C++11

  • 1、类型推导
    • 1.1 auto关键字
    • 1.2 auto类型推断本质
  • 2、类型计算
    • 2.1 类型计算分类
    • 2.2 类型计算的四种规则
    • 2.3 返回值类型计算
  • 3、列表初始化
  • 4、Lambda表达式
    • 4.1 前置知识
    • 4.2 Lambda表达式
    • 4.3 捕获表
  • 5、右值引用
    • 5.1 概念
    • 5.2 左值引用和右值引用
  • 6、移动语义

1、类型推导

1.1 auto关键字

  • C++98中,auto表示栈变量,通常省略不写
void foo(void){
	int i;
	auto int j;//表示在栈里分配的
}
  • C++11中,给auto赋予新的语义,表示自动类型推导
    • 既根据对变量进行初始化时所使用的数据的类型,由编译器自动推导出所定义变量的实际类型
auto i=0; -> int j=10;
auto j=i; -> int j=i;

1.2 auto类型推断本质

·按照定义独立对象并根据初始化数据的类型进行推导。
注意:无法自动推断const,只能自己在auto的上下文显示指明。但是有两种情况是除外的:
1:如果给出的初始化数据类型为常量指针,则可以自动推导出const
2:auto与引用的联合联用
- 按照定义独立对象并根据初始化数据的类型进行推导,所以不可能推导出引用
- 除非auto的上下文指明按照引用推导若指明按引用推导并且目标带有常属性,则可以自动推导const

/*类型推导  
linux 默认是c98标准的,如果需要编译的话需要添加 -std=c++11 
类型推导绝对不是类型照抄
*/
int main(){
	int a = 10;
	auto c = a;
	cout << "c的类型" << typeid(c).name() << endl;// typeid无法获取到对象的常属性
	c++;// 允许更改,说明不被const修饰
	cout <<"&c:"<< &c <<"&a:"<< &a << endl;
	
	const int b = 20;
	auto d = b;
	cout << "d的类型" << typeid(d).name() << endl;
	cout << "&d:" << &d<< "&b:" << &b << endl;
	d++;// 允许更改,说明不带const

	const auto e = b;// 自己在auto上添加const
	cout << "e的类型" << typeid(e).name() << endl;
	cout << "&e:" << &e << "&d:" << &d << endl;
	// e++;// 不允许更改,说明带const

	auto f = &b;// 如果初始化数据的类型为常指针,则可以自动推导出const
	cout << "f的类型为:" << typeid(f).name() << endl;
	// *f = 888; // *f不允许更改
	f = NULL; // f是可以更改,说明推导出来的类型是 const int *
	return 0;
}
/*类型推导和引用的联合使用*/
int main(){
	int a = 10;
	const int b = 10;

	auto & d = a;
	cout << "d的类型" << typeid(d).name() << endl; 
	cout << "&d:" << &d << "&a:" << &a << endl; // 地址相同,说明是别名
	d++;

	auto&e = b; // 这里指明了e是引用推导,并且b带有常属性,则可以自动推导出const
	cout << "e的类型" << typeid(e).name() << endl;
	cout << "&e:" << &e << "&b:" << &b << endl;// // 地址相同,说明是别名
	//e++; // 出错,说明不能更改 那么e的类型为const int &
	return 0;
}
  • auto关键字的使用限制
    • 1:函数形参类型无法推导(C++14标准支持)。
    • 2:类的成员变量无法推导。
void foo(auto v){}

2、类型计算

2.1 类型计算分类

c语言:sizeof-计算类型的大小
C++语言:typeid-可以获取类型的信息字符串
C++11:decltype-获取参数表达式的类型
注意事项:类型推导和类型计算都是由编译器确定,并不是运行期确定

/*类型计算*/
int main(){
	const int a = 10;
	auto  b = a; // 类型推导
	cout << "b的类型" << typeid(b).name() << endl; 
	cout << "&b:" << &b << "&a:" << &a << endl; 
	b++;// 允许更改,所以推导出来的类型是int
	decltype(a)c = 100;// 类型计算 初始值可以设置和a不一样
	cout << "c的类型" << typeid(c).name() << endl;
	cout << "&c:" << &c << "&a:" << &a << endl;// // 地址不相同相同
	// c++; // 出错,说明不能更改 那么c的类型为const int 
	return 0;
}
  • 类型推导和类型计算的比较
    1:类型计算比类型推导在类型的确定上更加精准
    2:类型计算比类型推导在初值的确定上更加灵活

2.2 类型计算的四种规则

  • 1:如果给decltype传递的为标识符表达式,decltype取该标识符的类型作为最终计算出的类型
int main(){
	int a = 10;
	// 如果给decltype传递的为标识符表达式,decltype取该标识符的类型作为最终计算出的类型
	decltype(a)b = a;// 类型计算
	cout << "b的类型" << typeid(b).name() << endl;
	cout << "&b:" << &b << "&a:" << &a << endl;// // 地址不相同
	b++; // 能更改说明b的类型为 int 
	return 0;
}
  • 2:如果给decltype传递的为函数表达式,decltype取该函数的返回值类型作为最终计算出的类型
float foo(){
	cout << "函数被调用" << endl;
	return 3.14;
}
int main(){
	int a = 10;
	// 如果给decltype传递的为函数表达式,decltype取该函数的返回值类型作为最终计算出的类型
	decltype(foo())b = a;// 并不会去实际调用foo()函数,类型计算是编译器确定的,不是运行时
	cout << "b的类型" << typeid(b).name() << endl;
	cout << "&b:" << &b << "&a:" << &a << endl;// // 地址不相同
	b++; // 能更改说明b的类型为 float 
	return 0;
}
  • 3:如果给decltype传递的为其他表达式,并且表达式的结果为左值,则取该左值引用的类型作为最终计算出的类型
int main(){
	int a = 10;
	// 如果给decltype传递的为其他表达式,并且表达式的结果为左值,则取该左值引用的类型作为最终计算出的类型
	decltype(++a)b = a;
	cout << "b的类型" << typeid(b).name() << endl;
	cout << "&b:" << &b << "&a:" << &a << endl;// // 地址相同
	b++; //允许更改 说明b的类型为int &
	return 0;
}
  • 4:如果给decltype传递的为其他表达式,并且表达式的结果为右值,则取该右值本身的类型作为最终计算出的类型
int main(){
	int a = 10;
	// 如果给decltype传递的为其他表达式,并且表达式的结果为右值,则取该右值本身的类型作为最终计算出的类型
	decltype(a++)b = a;
	cout << "b的类型" << typeid(b).name() << endl;
	cout << "&b:" << &b << "&a:" << &a << endl;// // 地址不相同
	b++; //允许更改 说明b的类型为int 
	return 0;
}

2.3 返回值类型计算

  • 返回值类型后置
auto foo(int x, double y)->decltype(x+y){// 返回值类型后置,通过decltype计算得出
	return  x + y;
}
int main(){
	auto f = foo(1, 3.1);// 类型推导
	cout << typeid(f).name() << endl; // double类型
	return 0;
}

3、列表初始化

基本类型,类类型,结构/联合/枚举类型等等的单个对象或对象数组,都可以采用形式完全统一的列表初始化语法
进行对象的初始化

  • 书写形式:类型 对象 {初值表};
    -int a{123);
    -new double {1.23);
    -string c{“123”};
    -struct Student {d,“张飞”,20,{1997,10,10}};
    -float e[]{1.1,2.2,3.3};
struct BD{
	int m_year;
	int m_month;
	int m_day;
};
struct myStudent{
	string m_name;
	int m_age;
	BD m_body;
};
class Human{
public:
	Human(int age = 0, const char* name = "无名") :m_age(age), m_name(name){

	}
	int m_age;
	string m_name;
};
int main(){
	int a = { 123 }; // int a=123
	cout << "a=" << a << endl;

	double* pa = new double{ 3.14 };// double *pa = new double(3.14);
	double *pb{ new double{ 3.14 } };
	cout << "*pa=" << *pa << " *pb=" << *pb << endl;

	int b[]{1, 2, 3};//int b[] = { 1, 2, 3 };
	for (int i = 0; i < 3; i++){ cout << b[i] << ' '; }
	int *parr{ new int[3]{4, 5, 6} };
	for (int i = 0; i < 3; i++){ cout << parr[i] << ' '; }
	delete[]parr;
	myStudent s{ "zs", 22, { 1997, 5, 7 } }; // myStudent s = { "zs", 22, { 1997, 5, 7 } };
	cout << s.m_name << s.m_age << s.m_body.m_year << s.m_body.m_month << s.m_body.m_day << endl;

	Human h{ 20, "赵云" };//Human h (20, "赵云" )
	cout << h.m_age << h.m_name << endl;
	return 0;
}
  • 小括号操作符函数
class AA{
public:
	int operator()(int x, int y){
		return x + y;
	}
};
int main(){
	AA a;
	cout << a(100, 200) << endl;;// a.operator()(100,200)
}

4、Lambda表达式

4.1 前置知识

在C++中函数的作用域中可以有类型,也可以有表达式

  • 针对于函数内部定义了类型,编译器先编译函数内部的类型,然后在编译函数体本身的代码
int a;
void foo(int b){
	int c;
	class A{
	public:
		void bar(int d){
			a = 0;// 能访问
			// b = 0; // 不能访问
			// c = 0; // 不能访问
			d = 0;// 能访问
		}
	};
}

4.2 Lambda表达式

  • 语法规则:
[捕获表](参数表)选项->返回类型
{
	函数体
}
  • 使用
int main(void){
	int a = 10, b = 20;
	auto c =[](int x, int y)->int{return x > y ? x : y; };
	// 编译器 (1) 生成一个类  (2) 类内定义一个小括号操作符函数 (3) 返回这个类的匿名对象
	cout<<c(a,b)<<endl;
	return 0;
}
  • 本质
    lambda表达式本质其实是一个类并且最终返回值为这个类的对象,因此对lambda表达式的调用就是该对象的函数操作符的调用
    在这里插入图片描述

解释:编译器在编译到Lambda表达式时,编译器会生成一个类Z4XXX的类,类中定义一个小括号操作函数,函数体里面填充Lambda的函数体内容,函数的返回值类型为Lambda中定义的返回类型。
其中

  • 可以没有返回值类型,将根据return推断
int main(void){
	int a = 10, b = 20;
	auto c = [](int x, int y){return x + y; };// 当没有返回值类型时,中间的箭头可以省略
	cout << c(a, b) << endl;
	return 0;
}
  • 如果连return也没有,则返回值为void
int main(void){
	int a = 10, b = 20;
	[](int x, int y){cout<< x + y<<endl; }(a,b);// 如果连return也没有,则返回值为void
	return 0;
}
  • 参数为void可以省略不写的
int main(void){
	int a = 10, b = 20;
	[]{cout << "12345" << endl; }();// 如果没有形参,返回值类型也为void那么小括号和中间的剪头都可以省略
	return 0;
}

4.3 捕获表

  • []-不捕获任何外部变量
  • [variable]-捕获外部变量的值
  • [&variable]-按引用捕获,外部变量的别名
  • [this]-捕获this指针,访问外部对象的成员
int a = 10;
class Y{
public:
	Y(int m_e) :e(m_e){};
	void foo(int c = 30){
		cout << "---" << endl;
		// []-不捕获外部变量的值
		[](int d = 40){
			cout << "a=" << a << endl;
			cout << "b=" << b << endl;
			// cout << "c=" << c << endl; // 错误
			cout << "d=" << d << endl;
			// cout << "e=" << e << endl; // 错误
		}();
		cout << "--------------[c]--------" << endl;
		// [variable]-捕获外部变量只读
		[c](int d = 0){cout << "c=" << c << endl; }();
		cout << "--------[&c]---------" << endl;
		// [&variable]-按引用捕获,外部变量的别名
		[&c]{c++; cout << "c=" << c << endl; }();
		cout << c << endl;
		// [this]-捕获this指针,访问外部对象的成员
		cout << "--------[this]---------" << endl;
		[this]{cout << "e=" << e << endl; }();
	}
private:
	static int b;
	int e;
};
int Y::b = 10;

int main(){
	Y y(4);
	y.foo();
	return 0;
}
  • [=]-按值捕获所有的外部变量,也包括this
  • [&]-按引用捕获所有的外部变量,也包括his
  • [=,&variable]-按值捕获所有的外部变量包括this,但是指定的外部变量按引用捕获。
  • [&,=variable]-按引用捕获所有的外部变量,也包括this,但是指定的外部变量按值捕获。

5、右值引用

5.1 概念

左值引用是别名,右值引用就是真名
左值:可以“取”地址的值就是左值,左值通常具名
右值:不可“取”地址的值就是右值,右值通常匿名
左值细分为非常左值和常左值
- 非常左值:有名字、可以取地址、没有常属性
- 常左值:有名字、可以取地址、有常属性
右值细分为纯右值和将亡值
- 纯右值:有一块无名内存,里面存放了基本类型的数据
- 将亡值:有一块无名内存,里面存放了类类型的数据

5.2 左值引用和右值引用

  • 左值引用只能引用左值,不能引用右值
  • 右值引用只能引用右值,不能引用左值
  • 常左值引用,既能引用左值,也能引用右值
  • 常右值引用,完全可以被常左值引用替代
/*左值引用和右值引用的差别*/
int main(){
	// 左值引用只能引用左值,不能引用右值
	int a=1, c=2;
	int & ra = a;
	// int & rb = a + c; // 错误 左值引用不能引用右值
	int &&rb = a + c;// 使用右值引用
	// int &&rc = a;// 错误 右值引用只能引用右值,不能引用左值
	cout << rb << endl;
	const int & _l = a; // 引用左值
	const int & _r = a + c; // 引用右值
	// 常左值引用会丧失修改目标的权限
	// _l = 9;// 错误
	// 右值引用不会丧失修改目标的权限
	rb = 90;
	cout << rb << endl;
}

6、移动语义

  • 方法:
    资源的转移 代替 资源的重建
  • 作用:
    保证功能正确的情况下,做到性能提升
//深拷贝构造函数 资源的重建
 String(const String & that) :m_psz(new char[strlen(that.m_psz) + 1]){
    cout << "深拷贝构造 资源的重建" << endl;
    strcpy(m_psz, that.m_psz); // 没有复制地址,复制了数据(深拷贝)
}
// 深拷贝构造函数 资源的转移 
String(String && that):m_psz(that.m_psz){
	that.m_psz = NULL;
	cout << "资源转移" << endl;
}
// 深拷贝赋值函数 资源的重建
 String& operator=(/*String* this*/const String & that){
	cout<<"深拷贝赋值函数 资源的重建"<<endl;
	if (this == &that){}// 防止出现用户自己给自己赋值
	else{
		delete[] this->m_psz;// 编译器会先定义一个m_psz,并初始>化为空串,所以需要先释放内存
		this->m_psz = new char[strlen(that.m_psz) + 1];// 申请新资源
		strcpy(m_psz, that.m_psz); // 拷贝新内容
	}
	return *this;// 返回自引用
}

// 拷贝赋值函数 资源的转移
String& operator=(String&& that){
	cout<<"拷贝赋值函数 资源的转移"<<endl;
	delete this->m_psz;
	this->m_psz=that.m_psz;
	that.m_psz=NULL;
	return *this;
}
//在linux下 命令行输入:g++ abc.cpp -std=c++11 -fno-elide-constructors
int main(){ 
	String s1=String("hello"); // 深拷贝构造函数 资源的转移
	String s2=s1;// 拷贝构造函数 资源的重建
	s2=s1;// 拷贝赋值函数 资源的重建
	s2=String("hello");// 拷贝赋值函数 资源的转移
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1829466.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1992-2023年各省产业结构升级、产业结构高级化数据(含原始数据+计算过程+计算结果)(无缺失)

1992-2023年各省产业结构升级、产业结构高级化数据&#xff08;含原始数据计算过程计算结果&#xff09; 1、时间&#xff1a;1992-2023年 2、来源&#xff1a;国家统计局、统计年鉴 3、指标&#xff1a;国内生产总值、第一产业增加值、第二产业增加值、第三产业增加值、第一…

N32G031 ADC初始化

目录 1. ADC初始化概述 2. ADC初始化详细步骤 2.1 ADC配置 2.2 ADC初始化函数调用 2.3 DMA配置&#xff08;可选&#xff09; 3. 初始化结果验证 4. 注意事项 ADC采样注意事项 1. ADC初始化概述 在N32G031单片机中&#xff0c;ADC的初始化是确保ADC模块能够正常工作的…

上海计算机考研避雷,25考研慎报

上大计算机一直很热 408考研er重来没有让我失望过&#xff0c;现在上大的专业课是11408&#xff0c;按理说&#xff0c;这个专业课的难度是很高的&#xff0c;但是408er给卷出了新高度&#xff0c;大家可以去上大官网看看今年最新的数据&#xff0c;我也帮大家统计了24年最新的…

图像处理:Python使用OpenCV进行图像锐化 (非锐化掩模、拉普拉斯滤波器)

文章目录 非锐化掩模 (Unsharp Masking)拉普拉斯滤波器 (Laplacian Filter)效果对比总结 在图像处理中&#xff0c;锐化操作用于增强图像的边缘和细节&#xff0c;使图像看起来更清晰。常见的图像锐化方法包括非锐化掩模&#xff08;Unsharp Masking&#xff09;和拉普拉斯滤波…

药品销售管理系统带万字文档药店管理系统java项目药店商城网站

文章目录 药品销售管理系统一、项目演示二、项目介绍三、万字项目文档四、部分功能截图五、部分代码展示六、底部获取项目源码带万字文档&#xff08;9.9&#xffe5;带走&#xff09; 药品销售管理系统 一、项目演示 药品销售管理系统 二、项目介绍 系统角色&#xff1a;管理…

【Python】深入了解 AdaBoost:自适应提升算法

我们都找到天使了 说好了 心事不能偷藏着 什么都 一起做 幸福得 没话说 把坏脾气变成了好沟通 我们都找到天使了 约好了 负责对方的快乐 阳光下 的山坡 你素描 的以后 怎么抄袭我脑袋 想的 &#x1f3b5; 薛凯琪《找到天使了》 在机器学习的领域中&#x…

学会这8点小技巧,让你公众号永不断更!

最近在带大家玩公众号 IP 写作&#xff0c;如何才能保持日更&#xff0c;是很多新手小白常问的问题&#xff0c; 这里我给大家总结了8点小技巧&#xff0c;分享给大家&#xff0c;让你的公众号写作&#xff0c;能够永远不断更&#xff01; 1&#xff0c;尽量早点做 &#xff0c…

Linux、Windows安全加固

为了减少系统被黑客入侵&#xff0c;对操作系统的安全加固是网络安全和主机安全必不可少的一部分。 一、Linux安全加固 1.不使用默认的ssh端口&#xff0c;修改默认ssh22端口号 sudo vim /etc/ssh/ssh_config 去掉#注释&#xff0c;修改端口号并保存 2.关闭不必要的系统服务…

对不起了,QQ和微信,我选择用它!

哈喽&#xff0c;各位小伙伴们好&#xff0c;我是给大家带来各类黑科技与前沿资讯的小武。 每当我们需要在电脑和手机之间传输文件、在学习和工作时与朋友/同事传输文件&#xff0c;相信大多都会使用微信或者QQ。 但是在分享一些软件apk等安装包时&#xff0c;微信和QQ会将其…

牛客 第二十届西南科技大学ACM程序设计竞赛(同步赛):祖玛

题目描述 wzy 在玩一种很新的祖玛。 给定一个仅包含 小写字母 的字符串 sss , sss 由 mmm 个不同的小写字母组成&#xff0c;每个字母代表一种小球&#xff0c;在消去时会获得 相应 的分数&#xff1a; 两个及以上 相同的小球相碰就会消失&#xff08;在发射小球前因为无相碰&…

PyTorch计算机视觉入门:测试模型与评估,对单帧图片进行推理

在完成模型的训练之后&#xff0c;对模型进行测试与评估是至关重要的一步&#xff0c;它能帮助我们理解模型在未知数据上的泛化能力。本篇指南将带您了解如何使用PyTorch进行模型测试&#xff0c;并对测试结果进行分析。我们将基于之前训练好的模型&#xff0c;演示如何加载数据…

DIVE INTO DEEP LEARNING 36-49

文章目录 36. Data augmentation36.1 Training with enhanced data36.2 Enhancement measures36.3 Data augmentation summary 37. Fine tuning37.1 Fine tuning Introduce37.2 Fine tuning Step37.3 Fine tuning summary 38. Object detection38.1 Object detection38.2 Edge …

设计模式之工厂方法模式(Factory Method Pattern)

目录 1.1、前言1.2、工厂方法模式简介1.2.1、工厂方法模式的主要特点1.2.2、工厂方法模式的主要结构1.2.3、使用工厂方法模式的好处 1.3、SpringBoot中那些场景使用了工厂方法模式1.4、日常工作中那些业务场景可以使用工厂方法模式1.5、工厂方法模式实战&#xff08;以某商场一…

Windows系统下使用gvim配置LaTeX快速书写环境

0 前言 小白近来读到这样一篇文章&#xff1a;How I’m able to take notes in mathematics lectures using LaTeX and Vim&#xff0c;这位学数学的小哥&#xff0c;通过使用vim和 LaTeX \LaTeX{} LATE​X在整个本科学习期间&#xff0c;共记下了1700多页的数学公式笔记&…

C/C++ Adaline自适应线性神经网络算法详解及源码

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

C++11参数包...Args

以list中的包装器做介绍 包装器是由一个类模板接收后存储在统一的...Args中 标准格式 说明&#xff1a;...Args就是参数包的类型 实例&#xff1a; //参数包 void Show() {cout <<"结束" << endl; }template<class T,class ...Args> void Show(T…

跟着刘二大人学pytorch(第---13---节课之RNN高级篇)

文章目录 0 前言0.1 课程视频链接&#xff1a;0.2 课件下载地址&#xff1a; 1 本节课任务描述模型的处理过程训练循环初始化分类器是否使用GPU构造损失函数和优化器每个epoch所要花费的时间遍历每个epoch时进行训练和测试记录每次测试的准确率加入到列表中 具体实现&#xff0…

哇塞,超好吃的麻辣片,一口就爱上

最近&#xff0c;我发现了一款让人欲罢不能的美食——食家巷麻辣片&#xff01;&#x1f60d; 一打开包装&#xff0c;那浓郁的麻辣香气就扑鼻而来&#xff0c;瞬间刺激着我的嗅觉神经。&#x1f603;食家巷麻辣片的外观色泽鲜艳&#xff0c;红通通的一片&#xff0c;看着就特…

Verilog综合出来的图

Verilog写代码时需要清楚自己综合出来的是组合逻辑、锁存器还是寄存器。 甚至&#xff0c;有时写的代码有误&#xff0c;vivado不能识别出来&#xff0c;这时打开综合后的schematic简单查看一下是否综合出想要的结果。 比如&#xff1a;误将一个always模块重复一遍&#xff0c;…

Java环境安装

下载JDK https://www.oracle.com/cn/java/technologies/downloads/#jdk22-windows 点开那个下载都可以但是要记住下载的路径因为下一步要添加环境变量 选择编辑系统环境变量 点击环境变量 点击新建 新建环境变量JAVA_HOME 并输入JDK在计算机保存的路径 打开cmd 输入java -…