【C++进阶】C++11基础

news2024/11/24 14:34:12

文章目录

  • 一、C++11简介
  • 二、统一的列表初始化
    • 1. {}初始化
    • 2、std::initializer_list
  • 三、 声明
    • 1.auto
    • 2. decltype
    • 3.nullptr
  • 三、范围for

一、C++11简介

  • 在2003年C++标准委员会曾经提交了一份技术勘误表(简称TC1),使得C++03这个名字已经取代了C++98称为C++11之前的最新C++标准名称。
  • 不过由于C++03(TC1)主要是对C++98标准中的漏洞进行修复,语言的核心部分则没有改动,因此人们习惯性的把两个标准合并称为C++98/03标准。
  • 相比于C++98/03,C++11则带来了数量可观的变化,其中包含了约140个新特性,以及对C++03标准中约600个缺陷的修正,这使得C++11更像是从C++98/03中孕育出的一种新语言。
  • C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大,而且能提升程序员的开发效率,公司实际项目开发中也用得比较多,所以我们要作为一个重点去学习。

二、统一的列表初始化

1. {}初始化

在C++98中,标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定。比如:

struct Point
{
	int _x;
	int _y;
};
int main()
{
	//可以使用大括号对数组和结构体初始化,但是不能省略=符号
	int array1[] = { 1, 2, 3, 4, 5 };
	int array2[5] = { 0 };
	Point p = { 1, 2 };
	return 0;
}

C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自
定义的类型,使用初始化列表时,可添加等号(=),也可不添加。

struct Point
{
	int _x;
	int _y;
};
int main()
{
	int x1 = 1;
	int x2{ 2 };
	int array1[]{ 1, 2, 3, 4, 5 };
	int array2[5]{ 0 };
	Point p{ 1, 2 };//C++11中可以省略等号(=)
	// C++11中列表初始化也可以适用于new表达式中
	int* pa = new int[4] { 0 };//此处不能加上等号(=)
	return 0;
}

创建对象时也可以使用列表初始化方式调用构造函数初始化

class Date
{
public:
	Date(int year, int month, int day)
		:_year(year)
		, _month(month)
		, _day(day)
	{
		cout << "Date(int year, int month, int day)" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2022, 1, 1); // old style
	// C++11支持的列表初始化,这里会调用构造函数初始化
	Date d2{ 2022, 1, 2 };
	Date d3 = { 2022, 1, 3 };
	return 0;
}

所以说,上边的三种方式都是初始化,都会调用构造函数。
在这里插入图片描述

2、std::initializer_list

我们可以使用typeid知道什么是initializer_list类型:

int main()
{
	// the type of il is an initializer_list 
	auto il = { 10, 20, 30 };
	cout << typeid(il).name() << endl;
	return 0;
}

在这里插入图片描述
std::initializer_list使用场景:
std::initializer_list一般是作为构造函数的参数,C++11对STL中的不少容器就增加std::initializer_list作为参数的构造函数,这样初始化容器对象就更方便了。也可以作为operator=的参数,这样就可以用大括号赋值,例如vector容器支持了std::initializer_list一般是作为构造函数的参数:
在这里插入图片描述

int main()
{
	vector<int> v1{1, 2, 3, 4, 5};
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
	vector<int> v2 = {1, 2, 3, 4, 5};
	for (auto e : v2)
	{
		cout << e << " ";
	}
	return 0;
}

以上两种方法均可对vector进行初始化。
在这里插入图片描述


我们之前模拟实现过vector容器,并且initializer_list支持迭代器,所以要实现使用initializer_list进行构造或者赋值就很简单:

namespace tmt
{
	template<class T>
	class vector
	{
	public:
		typedef T* iterator;
		vector(initializer_list<T> l)
		{
			_start = new T[l.size()];
			_finish = _start + l.size();
			_endofstorage = _start + l.size();
			//迭代器实现
			iterator vit = _start;
			typename initializer_list<T>::iterator lit = l.begin();
			while (lit != l.end())
			{
				*vit++ = *lit++;
			}
			//范围for实现
			//for (auto e : l)
			//   *vit++ = e;
		}
		vector<T>& operator=(initializer_list<T> l)
		{
			//复用构造函数
			vector<T> tmp(l);
			std::swap(_start, tmp._start);
			std::swap(_finish, tmp._finish);
			std::swap(_endofstorage, tmp._endofstorage);
			return *this;
		}

		iterator begin()
		{
			return _start;
		}

		iterator end()
		{
			return _finish;
		}
	private:
			iterator _start;
			iterator _finish;
			iterator _endofstorage;
	};
	void test()
	{
		vector<int> v1{1, 2, 3, 4, 5};
		v1 = { 5,4,3,2,1 };

		for (auto e : v1)
		{
			cout << e << " ";
		}
	}
}

int main()
{
	tmt::test();
	return 0;
}

在这里插入图片描述
注意:

使用typename initializer_list::iterator lit,即迭代器时要加上typename,因为编译器可能不会把initializer_list识别为一个类型,而会识别成一个变量,使用typename关键字修饰,编译器才会将这个名字视为类型。

三、 声明

c++11提供了多种简化声明的方式,尤其是在使用模板时。

1.auto

在C++98中auto是一个存储类型的说明符,表明变量是局部自动存储类型,但是局部域中定义局
部的变量默认就是自动存储类型,所以auto就没什么价值了。C++11中废弃auto原来的用法,将
其用于实现自动类型腿断。这样要求必须进行显示初始化,让编译器将定义对象的类型设置为初
始化值的类型。

int main()
{
	int i = 10;
	auto p = &i;
	cout << typeid(p).name() << endl;
	map<string, string> dict = { {"sort", "排序"}, {"insert", "插入"} };
	cout << typeid(dict).name() << endl;

	//auto也可以简化代码
	//map<string, string>::iterator it = dict.begin();
	auto it = dict.begin();
	return 0;
}

使用auto可以自动推导出类型,并且当类型名较长时,可以使用auto来简化代码。


但是使用auto时,也有很多要注意的地方:

int main()
{
	short a = 32670;
	short b = 32670;
	//c如果给成short,会造成数据丢失,如果能够让编译器根据a+b的结果推导c的实际类型,就不会存在问题
	short c = a + b;
	cout << c << endl;
	auto d = a + b;
	cout << d << endl;
	return 0;
}

在这里插入图片描述

2. decltype

关键字decltype将变量的类型声明为表达式指定的类型。
decltype与typeid不同的是,可以直接可以获得的类型可以直接定义变量。

// decltype的一些使用使用场景
template<class T1, class T2>
void F(T1 t1, T2 t2)
{
	decltype(t1 * t2) ret;
	cout << typeid(ret).name() << endl;
}
int main()
{
	const int x = 1;
	double y = 2.2;
	decltype(x * y) ret;
	decltype(&x) p;
	cout << typeid(ret).name() << endl;
	cout << typeid(p).name() << endl;
	F(1, 'a');
	return 0;
}

3.nullptr

由于C++中NULL被定义成字面量0,这样就可能回带来一些问题,因为0既能指针常量,又能表示
整形常量。所以出于清晰和安全的角度考虑,C++11中新增了nullptr,用于表示空指针。

#ifndef NULL
#ifdef __cplusplus
#define NULL   0
#else
#define NULL   ((void *)0)
#endif
#endif

由于NULL被定义为0,所以可能在下边的情况中存在问题:
由于NULL和nullptr本意都是空指针,所以在进行匹配时应该匹配到int*处,但是NULL会匹配0,所以在使用时使用nulllptr更加清晰安全。

void f(int arg)
{
	cout << "void f(int arg)" << endl;
}
void f(int* arg)
{
	cout << "void f(int* arg)" << endl;
}
int main()
{
	f(NULL);    //void f(int arg)
	f(nullptr); //void f(int* arg)
	return 0;
}

三、范围for

在C++11范围for出现以前,我们在进行遍历数组时,需要以下的方式:

	int arr[] = { 1,2,3,4,5,6,7,8,9 };
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		cout << arr[i] << " ";
	}

在使用时,可能会出现一些问题,使用范围for会减少错误:

	int arr[] = { 1,2,3,4,5,6,7,8,9 };
	for (auto e : arr)
	{
		cout << e << " ";
	}

由于范围for的本质就是通过迭代器遍历,所以我们熟知的STL容器也可以直接使用范围for进行遍历:

	string str = "hello world";
	for (auto& e : str)
	{
		cout << e << " ";
	}

在这里插入图片描述


由于范围for的本质就是通过迭代器进行遍历,所以在使用范围for时,必须满足下边的要求:

  • 数据必须有范围,对于数组必须提供第一个元素和最后一个元素的指针,而对于类而言必须提供begin和end函数
  • 迭代器必须提供++操作和==操作,因为迭代器遍历必须满足。

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

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

相关文章

Python3实现画小提琴图(包含分组)

说在前面 Python如何画一个小提琴图呢?先看下必备的数据集合(自己构建,样式参考) 默认必有X列、Y列(数值),画分组需要包含分组的列group等数据参数准备 可以参考下面的数据样例: 除此之外,对于画图使用的参数,提前准备的知识如下: sns.violinplot所必备的参数…

数据结构-堆排序代码实现(详解)

内容&#xff1a;堆排序的代码实现及注解&#xff0c;思路详解 代码实现&#xff1a; 交换函数&#xff1a; void Swap(int* p1, int* p2) {int tmp *p1;*p1 *p2;*p2 tmp; } 堆排序函数&#xff1a; 1 向下调整建堆函数&#xff1a;这里建立大堆&#xff0c;小堆思路也…

Litedram仿真验证(三):AXI接口完成仿真(FPGA/Modelsim)

日常唠嗑 不知不觉&#xff0c;从开始接触Litedram已经过去了4个月&#xff0c;期间断断续续做了好多其他任务&#xff0c;导致进度比较慢&#xff0c;直到前天才把Litedram完全仿真起来。&#xff08;坑很多&#xff0c;很多东西需要注意&#xff09; 目录 日常唠嗑一、AXI用…

C—数据的储存(下)

文章目录 前言&#x1f31f;一、练习一下&#x1f30f;1.例一&#x1f30f;2.例二&#x1f30f;3.例三&#x1f30f;4.例四 &#x1f31f;二、浮点型在内存中的储存&#x1f30f;1.浮点数&#x1f30f;2.浮点数存储&#x1f4ab;&#xff08;1&#xff09;.二进制浮点数&#x…

快速入门java微服务架构SpringBoot之一

Springboot概念&#xff1a; Springboot提供了一种快速使用Springboot的方式&#xff0c;基于约定优于配置的思想。 可以让开发人员不必在配置与逻辑业务之间进行思维的切换&#xff0c;全身心的投入到逻辑业务的代码编辑中&#xff0c;从而大大提高了开发的效率&#xff0c;…

matlab主成分分析算法在人脸识别的具体应用

主成分析&#xff08;Principal Component Analysis&#xff0c;简称PCA&#xff09;是一种常用的降维算法&#xff0c;可以将高维数据转化为低维数据&#xff0c;同时保留原始数据的最重要特征。PCA算法在人脸识别中有广泛的应用&#xff0c;可以提取人脸图像中的主要特征&…

《啊哈算法》第二章--队列 栈 链表

文章目录 前言一、数据结构基础知识(衔接知识)二、队列三、栈四、链表总结 前言 上一节我们学习了排序算法当中的快速排序 冒泡排序 桶排序 &#xff0c;那么本节得主要学习内容是队列 栈 链表得相关数据结构得知识 一、数据结构基础知识(衔接知识) 基于学习这本书得都是一些…

《英雄联盟》丢失d3dcompiler_47.dll怎么办,推荐这个修复方案

不知道大家有么有遇到过&#xff0c;在打开《英雄联盟》的时候&#xff0c;计算机提示丢失d3dcompiler_47.dll&#xff0c;无法继续执行此代码。d3dcompiler_47.dll是一个动态链接库文件&#xff0c;它是与Direct3D编译器相关的组件之一。像是photoshop等软件&#xff0c;英雄联…

IEEE754 标准是如何制定浮点数的存储的

1. IEEE754 标准简介 IEEE754 标准是一种用于浮点数表示和运算的标准&#xff0c;由国际电工委员会&#xff08;IEEE&#xff09;制定。它定义了浮点数的编码格式、舍入规则以及基本的算术运算规则&#xff0c;旨在提供一种可移植性和一致性的方式来表示和处理浮点数 IEEE754 …

c#使用ThreadPool

说到ThreadPool&#xff0c;都知道是线程池。在c#中&#xff0c;有很多方式可以实现线程。从时间上来排序&#xff0c;大概是这样的&#xff0c;Thread&#xff0c;backgroundworker&#xff0c;ThreadPool&#xff0c;Parallel&#xff0c;Task。其中后面2种是最新的&#xff…

第十八章:Auto-DeepLab:用于语义图像分割的层次化神经架构搜索

0.摘要 最近&#xff0c;神经架构搜索&#xff08;NAS&#xff09;已经成功地识别出在大规模图像分类任务上超越人工设计的神经网络架构。在本文中&#xff0c;我们研究了NAS在语义图像分割任务中的应用。现有的工作通常集中在搜索可重复的基本单元结构&#xff0c;而手动设计控…

一些有趣的Git学习资料

Git 可以说是程序员必备的技能之一了&#xff0c;基于 Github/Gitlab 以及相关工作流的使用&#xff0c;Git 已经融入到了我们的日常工作中&#xff0c;这里分享一些有趣的 Git 学习资料&#xff0c;希望可以帮助大家更好的理解 Git。 1. Welcome to Learn Git Branching 以动…

第二周笔记

public class Calc { //加法, 把和作为一个结果返回出去, 返回给调用者 public int add3(int num1, int num2){ if(num1 0 && num2 0){ return 0; //隐式包含一个if-else结构 } //使用return 关键字 return nu…

【Linux操作系统】多线程抢票逻辑——学习互斥量(锁)函数接口

文章目录 1.进程线程间的互斥相关背景概念2.联系代码学习同步互斥问题3.互斥量&#xff08;锁&#xff09;的函数接口3.1初始化互斥量3.2销毁互斥量3.3互斥量加锁和解锁3.4改进多线程抢票代码 1.进程线程间的互斥相关背景概念 临界资源&#xff1a;多线程执行流共享的资源就叫…

beego验证码(配置到redis存储)

我们定义一个全局变量用于存储redis连接 RedisDb *redis.Client 然后连接 redis 这一块我们将redis信息写到app.conf文件里了&#xff1a; redisDb 1 redisAddr "127.0.0.1:6379" redisPwd "" package initializeimport ("beego_learning/global&q…

【Java基础教程】(十四)面向对象篇 · 第八讲:多态性详解——向上及向下转型、关键字 final与 instanceof的作用~

Java基础教程之面向对象 第八讲 本节学习目标1️⃣ final 关键字1.1 final类1.2 final方法1.3 final属性 2️⃣ 多态性2.1 向上转型2.2 向下转型2.3 关键字 instanceof &#x1f33e; 总结 本节学习目标 掌握final 关键字的主要作用及使用&#xff1b;掌握对象多态性的概念以…

【CSDN新星计划】初阶牛C/C++赛道——顺序程序设计(C语句)

目录 3.1 C语句的作用和分类 &#x1f349;&#xff08;1&#xff09;控制语句 &#x1f349;&#xff08;2&#xff09;函数调用语句 &#x1f349;&#xff08;3&#xff09;表达式语句 &#x1f349;&#xff08;4&#xff09;空语句 &#x1f349;&#xff08;5&#…

【C++进阶之路】vector的基本使用和模拟实现

前言 作为STL的容器之一&#xff0c;vector的名字通常令人疑惑&#xff1f;在字面上&#xff0c;我们通常会翻译成向量&#xff0c;但感觉又解释不通&#xff0c;总觉得应该叫dynamic array翻译成动态数组/顺序表&#xff0c;更容易理解&#xff1f;那为啥呢&#xff1f; 我从…

【Java】微服务项目的部署

微服务项目的部署 准备Centos安装 Docker镜像加速检查加速器是否生效 下载docker-compose方法1 curl方法2 pip方法3 直接下载released 用docker-compose部署中间件导入项目安装jdk maven git设置idea内存减小jar启动占用内存增加idea可使用内存 本文参考 https://gitee.com/…

音乐怎么转换成wav格式?分享这五个方法给大家!

在音频编辑和处理过程中&#xff0c;将音乐文件转换为WAV格式是一种常见需求。WAV格式以其无损音质和广泛的兼容性而受到许多人的喜爱。下面介绍了五种常用的方法&#xff0c;帮助您将音乐文件转换为WAV格式&#xff0c;其中方法一使用记灵在线工具。 方法一&#xff1a;记灵在…