C++11:声明 初始化

C++11:声明 & 初始化

    • 初始化
      • { }初始化
      • initializer_list
    • 声明
      • auto
      • decltype
      • nullptr


初始化

{ }初始化

在C++98中,允许使用花括号{ }对数组或者结构体元素进行统一的列表初始化。

{ }初始化数组:

int arr[] = { 1, 2, 3, 4, 5 };

{ }初始化结构体:

struct stu
{char name[20];int age;
};int main()
{stu s1 = { "Jones", 18 };return 0;
}

C++11扩大了{ }的适用范围,其可以用于所有的内置类型和自定义类型的初始化

C++11希望通过这个语法,使得所有变量可以以一种统一的方式进行初始化

比如对于内置类型:

int i = { 1 };
double d = { 3.14 };
char c = { 'x' };int* pf = { nullptr };
int& ri = { i };

我们可以通过大括号初始化整型,浮点型,指针,引用等等。在使用{ }进行初始化时,可以省略掉= ,所以以上代码也可以写为:

int i{ 1 };
double d{ 3.14 };
char c{ 'x' };int* pf{ nullptr };
int& ri{ i };

但是这个语法其实也比较鸡肋,因为这个写法完全没有直接int i = 1;这样来的直接。

接着就是自定义类型的初始化:

struct stu
{char name[20];int age;
};int main()
{stu s{ "jack", 18 };string str{ "hello world" };int arr[5]{ 1, 2, 3, 4, 5 };return 0;
}

以上代码中,通过直接在变量后面加一对大括号来实现初始化,数组和结构体初始化时的=也可以省略掉。

在此,我要额外辨析一下现有的类的初始化方式:

现在有如下日期类:

class Date
{
public:Date(int year, int month, int day): _year(year),_month(month),_day(day){}private:int _year;int _month;int _day;
};

其含义三个变量,表示年月日,一个三参数的构造函数,初始化这个Date

我们有如下方式对其初始化:

Date d1(2024, 4, 3);
Date d2 = { 2024, 4, 3 };
Date d3{ 2024, 4, 3 };

请问这三个方式,分别是如何初始化一个类的?

  • 对于Date d1(2024, 4, 3);,其就是最基础的构造函数调用语法,也就是直接构造
  • 对于Date d2 = { 2024, 4, 3 };,很多人看到这个写法,再想到我们刚才讲的{ }初始化,以为这个是C++11的新语法,其实并不是的。这个写法是多参数构造函数的类型转化,也就是说这个写法{ 2024, 4, 3 };就是把三个int类型转换为Date类型。如果你用explicit关键字修饰这个构造函数,那么类型转换功能就会被禁止,这个写法就会报错
  • 对于Date d3{ 2024, 4, 3 };,这个写法即使用了{ },而且还省略了=,这就是C++11提供的新语法了,当用explicit修饰这个构造函数,这个写法依然有效。因为这个写法也是直接调用构造函数,而不是进行类型转换

其实整体上来说,C++11提供{ }的意图在于提供统一的方式来初始化所有类型,但是奈何大部分程序员已经习惯了之前的写法,{ }既没有带来效率的提高,也没有更加人性化的语法设计(甚至我感觉int i = 1int i(1);更符合人类的习惯),因此这个语法并没有被广泛接受。


initializer_list

initializer_list是一个新的C++类型,我先为大家创建一个initializer_list类型:

auto li = { 1, 2, 3, 4 };

此时,li的类型就是initializer_list,这个时候有的人就疑惑了,{ 1, 2, 3, 4 }分明是一个整型数组,怎么改了个名字就变成新类型了?initializer_list翻译为中文就是初始化列表,也就是说,这是一个用于初始化的工具

假设现在你有以下数组:

int arr[5] = { 1, 2, 3, 4 };

你要如何用这个数组来初始化一个vector,初始化一个list,初始化一个set呢?

我们好像只能粗暴的遍历数组,然后一个一个插入数据:

vector<int> v;
for (int i = 0; i < 5; i++)
{v.push_back(arr[i]);
}

这着实有点麻烦了,但是C++11后,STL的所有容器都增加了新的构造函数,可以通过initializer_list来初始化容器:

vector<int> v({ 1, 2, 3, 4, 5 });

以上代码中,{ 1, 2, 3, 4, 5 }整体就是一个initializer_list,作为参数传给v,调用vector的构造函数。

当然,我们也可以这样写:

vector<int> v = { 1, 2, 3, 4, 5 };

这个写法,则是单参数的类型转化,因为{ 1, 2, 3, 4, 5 }整体就是一个initializer_list类型的参数。

相同的办法,我们还可以初始化map

map<string, string> m = { {"apple","苹果"}, {"strawberry","草莓"}, {"watermelon", "西瓜"} };

以上代码中,最外层的{ }括起来的就是一个initializer_list,内部的三个{ }则是三个不同的pair<const char*, const char*>,不过const char*可以转为string,因此最后pair<const char*, const char*>会变成pair<string, string>

最外层的initializer_list内部的三个pair,会依次插入进map中,也就是一次拿多个值初始化map的多个节点。

至此,你应该理解了,initializer_list就是在类构造时,如果我们想要一次性初始化多个节点,就把这些节点放进一个initializer_list内部,这样就能在构造函数中直接构造好。

initializer_list本质上也是一个容器,一个类模板:
在这里插入图片描述
因此{ 1, 2, 3, 4, 5 }的准确类型应该是:initializer_list<int>

initializer_list的底层也非常简单,我们看看其仅有的四个接口:

在这里插入图片描述

一个构造函数constructor,一个描述长度的接口size,以及迭代器beginend也就是说initializer_list本质上是一个通过迭代器访问数组的容器。当其它容器通过initializer_list构造自己,其实就是通过迭代器遍历那个存储了节点的数组,然后把数组元素一个一个插入。

也就是说,以下两种情况,本质是一样的:

initializer_list<int> lt = { 1, 2, 3, 4 };list<int> l1({ 1, 2, 3, 4 });
list<int> l2(lt.begin(), lt.end());

第一个list通过initializer_list初始化自己,第二个list则通过迭代器初始化自己。不过前者更加方便,是C++11提供的,而后者是C++98提供的。


声明

auto

在C++11中,新增了关键字auto,其可以自动推导类型:

auto i = 1;//整型
auto d = 3.14;//浮点型
auto p = &i;

此时i就会被自动识别为intd就自动识别为doublep自动识别为int*

auto的主要作用在于对于有一些类型,它的长度太长了,我们就可以用auto一笔带过。

比如完整地定义一个迭代器:

vector<int> v;
vector<int>::iterator it = v.begin();

但是我们可以用auto直接自动识别:

vector<int> v;
auto it = v.begin();

在定义迭代器的时候,auto的使用还是比较常见的。


decltype

在C++11以前,有一个关键字typeid,其可以识别一个类型,并且可以通过name成员函数来输出类型名。

比如这样:

int i = 0;
int* pi = &i;cout << typeid(i).name() << endl;
cout << typeid(pi).name() << endl;

输出结果为:

int
int * __ptr64

也就是说,我们可以通过typeid来检测甚至输出变量类型。

decltype也是用于识别类型的,但是decltypetypeid应用方向不同。

decltype可以检测一个变量的类型,并且拿这个类型去声明新的类型

比如这样:

int i = 0;
decltype(i) x = 5;

decltype(i)检测出i的类型为int,于是decltype(i)整体就变成int,从而定义出一个新的变量x


nullptr

在C++11后,推出了新的空指针nullptr,明明已经有NULL了,为啥还需要nullptr?

NULL在C语言中,表示的是((void*)0),也就是被强制转为void*类型的0。但是在C++中,NULL就是整数0

比如可以用刚才学的typeid验证一下:

cout << typeid(NULL).name() << endl;

输出结果为:int,这下就石锤了NULL在C++中就是int

这会导致不少问题,比如这样:

void func(int x)
{cout << "参数为整型" << endl;
}void func(void* x)
{cout << "参数为指针" << endl;
}int main()
{func(NULL);return 0;
}

以上代码中,func函数有两个重载,一个是参数为指针,一个是参数为整型。我现在就是想传一个空指针去调用指针版本的func。但是最后还是会调用int类型的。

nullptr不一样,nullptr不仅不是整型,而且其也不是void*。C++给了nullptr一个专属类型nullptr_t。这个类型有一个非常非常大的优势,该类型只能转化为其它指针类型,不能转化为指针以外的类型

比如以下代码:

int x1 = NULL;//正确
int x2 = nullptr;//错误

因为NULL本质是0,其可以转化为很多非指针类型,比如intdoublechar。但是nullptrnullptr_t,它只能转化为其他指针。上述代码中,我们把nullptr转化为一个int,此时编译器会直接报错,绝对禁止这个行为。

但是这样是可以的:

void* p1 = nullptr;
int* p2 = nullptr;
char* p3 = nullptr;
double* p4 = nullptr;

可以看到,nullptr保证了指针类型的稳定,空指针不会被传递到指针以外的类型。因此nullptr在各方面都有足够的优势,以更加安全的形式给用户提供空指针。


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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt C++ | Qt 元对象系统、信号和槽及事件(第一集)

01 元对象系统 一、元对象系统基本概念 1、Qt 的元对象系统提供的功能有:对象间通信的信号和槽机制、运行时类型信息和动态属性系统等。 2、元对象系统是 Qt 对原有的 C++进行的一些扩展,主要是为实现信号和槽机制而引入的, 信号和槽机制是 Qt 的核心特征。 3、要使用元…

VMware虚拟机三种网络模式配置

vmware有三种网络工作模式&#xff1a;Bridged&#xff08;桥接模式&#xff09;、NAT&#xff08;网络地址转换模式&#xff09;、Host-Only&#xff08;仅主机模式&#xff09;。 1. 打开网络编辑器&#xff08;编辑 --> 虚拟网络编辑器&#xff09; 在主机上有VMware Ne…

【阿里淘天笔试题汇总】2024-04-03-阿里淘天春招笔试题(第一套)-三语言题解(CPP/Python/Java)

&#x1f36d; 大家好这里是KK爱Coding &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新淘天近期的春秋招笔试题汇总&#xff5e; &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f…

[RK3588-Android12] 调试MIPI-双通道-压缩屏(Video Mode/MIPI Dphy 8Lane/DSC 144HZ)

问题描述 被测屏幕&#xff1a;小米Pad6 分辨率&#xff1a;1800X2880 模式&#xff1a;Video Mode/MIPI Dphy 8Lane/DSC 144HZ PPS: 11 00 00 89 30 80 0B 40 03 84 00 14 01 C2 01 C2 02 00 01 F4 00 20 01 AB 00 06 00 0D 05 7A 06 1A 18 00 10 F0 03 0C 20 00 06 0B 0B 33…

[Leetcode笔记] 动态规划相关

前言 写题目写到了一些和动态规划相关的内容&#xff0c;所以在这里记录一下 LCR 089 题解思路 总的来说&#xff0c;就是用一个数组去存储当前的最优解&#xff0c;然后从0开始一路向上顺推过去&#xff0c;求得最后一位的最优解。 class Solution { public:int rob(vect…

k8s calico由IPIP模式切换为BGP模式

按照官网calico.yaml部署后&#xff0c;默认是IPIP模式 查看route -n &#xff0c; 看到是tunl0口进行转发 怎么切换到BGP模式呢&#xff1f; kubectl edit ippool 将ipipMode由Always修改为Never &#xff0c;修改后保存文件即可。无需做任何操作&#xff0c;自动就切换为BG…

公众号爆文策略与实践:揭秘千万阅读量的秘密

1. 引言 介绍公众号爆文的重要性&#xff0c;以及分享个人通过每天投入半小时赚到30倍门票的经验。强调跟上大佬步伐&#xff0c;提升认知的重要性。 2. 爆文的底层逻辑 2.1 推荐的底层逻辑 内容分发机制的变化&#xff0c;从仅限于直接关注到通过搜索、浏览推荐等多种方式…

【详解】Windows系统安装Nginx及简单使用

【详解】Windows系统安装Nginx及简单使用 一、Nginx是什么&#xff1f; “Nginx 是一款轻量级的 HTTP 服务器&#xff0c;采用事件驱动的异步非阻塞处理方式框架&#xff0c;这让其具有极好的 IO 性能&#xff0c;时常用于服务端的反向代理和负载均衡。”Nginx 是一款 http 服…

实景三维:城市数据要素的新维度

引言 在数字化转型的大潮中&#xff0c;数据已成为推动社会发展的关键要素。实景三维技术&#xff0c;作为一种新兴的数据表达形式&#xff0c;正在成为城市数据要素中不可或缺的一部分。它不仅丰富了数据的类型&#xff0c;更为城市规划、管理和服务提供了全新的视角。本文将…

N1912A安捷伦N1912A功率计

181/2461/8938产品概述&#xff1a; 安捷伦N1912A双通道P系列宽带功率传感器为R&D和制造工程师提供精确和可重复的功率测量&#xff0c;应用市场包括航空航天和国防&#xff08;雷达&#xff09;、无线通信和无线802.11a/b/g网络。该仪表/传感器组合提供的测量包括峰值功率…

QT-自定义参数设计框架软件

QT-自定义参数设计框架软件 前言一、演示效果二、使用步骤1.应用进行参数注册2.数据库操作单例对象3.参数操作单例对象 三、下载链接 前言 常用本地数据参数通常使用的是xml等文本的格式&#xff0c;进行本地的数据参数的存储。这种参数的保存方式有个致命的一点&#xff0c;就…

基于单片机20v数字电压表仿真系统设计

**单片机设计介绍&#xff0c;基于单片机20v数字电压表仿真系统设计 文章目录 一 概要二、功能设计三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机20V数字电压表仿真系统设计的主要目标是实现一个能够准确测量和显示20V直流电压的仿真系统。以下是该设计的主…

Sy6 编辑器vi的应用(+shell脚本3例子)

实验环境&#xff1a; 宿主机为win11&#xff0c;网络&#xff1a;10.255.50.5 6389 WSL2 ubuntu 目标机的OS&#xff1a;Ubuntu 内核、版本如下&#xff1a; linuxpeggy0223:/$ uname -r 5.15.146.1-microsoft-standard-WSL2 linuxpeggy0223:/$ cat /proc/version Linux vers…

VMware创建Ubuntu虚拟机详细教程

下载ISO映像文件 进入官网下载&#xff1a;Download Ubuntu Desktop | Download | Ubuntu 下面是一些其他的下载路径&#xff1a; 中国官网 https://cn.ubuntu.com/ 中科大源 Index of /ubuntu-releases/ (ustc.edu.cn) 阿里云开源镜像站 ubuntu-releases安装包下载_开源镜像…

真·面试题总结——JVM虚拟机

JVM虚拟机 JVM虚拟机规范与实现 JVM虚拟机规范 JVM虚拟机实现 JVM的常见实现 JVM虚拟机物理架构 JVM虚拟机的运转流程 JVM类加载过程 JVM类加载器及类加载器类型 JVM类加载器双亲委派机制 JVM运行时数据区的内存模型 JVM运行时数据区的内存模型&#xff1a;程序计数器…

day08 java 静态方法调用 方法的内存实现机制

目录 静态方法调用 方法的内存实现 静态方法调用 静态方法&#xff1a; 静态方法要在方法上用修饰符static。 静态方法可以通过类名调用 &#xff1a;类名.方法名&#xff08;&#xff09;或者 直接调用 &#xff1a;方法名&#xff08;&#xff09; 在同一个类中时&#xf…

网工内推 | 国企运维,IA认证,大专以上即可,最高22K

01 深圳建广数字科技有限公司青岛分公司 招聘岗位&#xff1a;桌面运维工程师 职责描述&#xff1a; 1.根据运维服务请求完成关于操作系统、应用软件、办公设备、网络等方面的安装、管理与维护&#xff1b; 2.各种PC软硬件故障诊断、排查及升级&#xff1b; 3.桌面设备&…

自动化测试如何管理测试数据

前段时间&#xff0c;知识星球里有同学问到&#xff1a;自动化case越多&#xff0c;测试数据越多&#xff0c;数据的管理成本也越来越高&#xff0c;是否需要一个数据池来专门管理测试数据&#xff1f;这是一个好问题&#xff0c;也是很多测试同学在自动化测试实践中必须面对的…

新手使用GIT上传本地项目到Github(个人笔记)

亲测下面的文章很有用处。 1. 初次使用git上传代码到github远程仓库 - 知乎 (zhihu.com) 2. 使用Git时出现refusing to merge unrelated histories的解决办法 - 知乎

Lua环境下载与配置

这里介绍如何下载已经编译好的Lua环境&#xff0c;如何配置Lua环境。 如希望自己从源码编译Lua环境&#xff0c;请自行搜索资料。 第一步&#xff1a;下载编译好的lua环境 打开下面链接&#xff0c;然后根据指引下载。 The Programming Language Luahttps://www.lua.org/hom…