C++直接初始化和复制初始化

C++ 笔记1——explicit关键字、构造函数与对象初始化 创建:2018/4/4;最近更新:2018/4/4写在前面    这几篇笔记不是那种讲解C++基础概念的入门级教程,也不是纷繁复杂、面面俱到的专家级教材。因为这两种资料在网络上或者是出版的书籍上已经够多了。在这里,我主要想记录自己在学习C++过程中遇到的一些细节问题和自己查阅资料之后对这些问题的理解。    C++是一门极其庞大的巨型语言,而我也是C++的初学者,因此我在学习和总结的过程中难免有认... 阅读详情

(1)复制初始化的基本原理
我们知道,对象在内存中的直接表象是在内存中占有一个一定大小的空间。分配空间是建立对象的第一步。但是刚刚分配的空间就像一个没有开垦的荒田,或者是前面对象占有之后留下来的残余,从理论上讲,由于不管是什么大家都是0101,所以就算没有初始化也是有值的,只是这个值你是不能正确使用的。所以建立对象的关键在于如何对该对象所占有的空间进行正确的初始化。

初始化虽然与赋值的结果很像,但是其所面临的状态和发生的时间是不同的。从他们的功能来讲,初始化与给某个变量赋值的唯一特点就是他是第一次初始化。当然当你认识到这点的时候,他们的区别也就是无所谓了。关键在于,初始化,是一个必须的赋值过程,因为如果你不做这方面的动作,你的对像是一个没有用的(或者不能正常使用的)

直接初始化,就是使用构造函数,定义在申请了对象空间之后如何对各个子空间进行初始赋值,称他们为直接初始化是很贴切的,应为他就是最为普通的初始化,是构建一个完整对象的一个过程——先将空间申请好,然后给各个子空间(数据属性)进行相应的赋值。

复制初始化,特点特别之处在于“复制”二字,核心意义就是,我通过对一个已有对象的完全复制,来构建对象。它的过程可以理解成这样——先申请空间,然后将被复制的对象(空间一样大)的所有内容全部复制过去,就形成了这个对象。所以,要明确,两种初始化的方式,都是一构造函数的形式存在的。区别在于他们的参数方面,复制初始化,表达的就是对一个已有同类型的对象进行复制,那么这种构造函数就应该使用某个对象来进行复制,同时因为,C++参数的传递默认都是值传递,要声明使用引用的方式(要不然就又复制了一次了);并且是const类型的。


也就是说任何复制初始化的表面特征就是使用“=”号来表达,左边是对该对象的空间的申明,右边是另外一个同类型的对象,注意,一定是同类型的对象(即使不是,也会使用类型转换构造函数来进行构造(前面说过)!形如:

classname objectname=objectname2;    //复制初始化。
classname objectname(,,,,,);    //直接初始化,有参数。
classname objectname;     //直接初始化,没有参数。
classname *objectpointorname=new classname(,,);   

这里的操作有两个过程,先使用对象构造函数通过直接初始化构造出一个对象,然后将指针放回,不管有没有参数。

classname objectname=other_objectname3;  

这里表达的是,这个othe_objectname3,不是classname这个类型。这个个就要知道,右边的会通过调用直接初始化构造函数,构造出对应的对象,然后调用复制初始化构造函数。



所以: 构造函数应该分为:1)直接初始化构造函数

                                              2)复制初始化构造函数

还是要说,复制初始化构造函数看起来像赋值,但是,其实只是像而已,它其实是借用了这种表象,来触发调用了那个使用同类型对象引用作为参数的复制构造函数。

string null_book="9-999-9999-9";    //先调用了隐式转换的直接初始化构造函数,然后调用了复制初始化构造函数。

string dots(10, '.');//直接调用直接初始化构造函数。

string empty_copy=string(); //先调用显示直接初始化构造函数,然后调用复制初始化构造函数。

string empty_direct;  //直接调用没有参数的(默认)构造函数

ifstream file1("filename");   //直接初始化

ifstream file2="filename";   //虽然语法没有错,但是,由于文件对象不能复制,所以不能使用复制初始化,这种做法在文件领域中通常是错误的。

Sales_item item=string("9-999-99999-9");  //这个语法对与错,关键是看Saltes_item有没有隐式(没有使用explicity标志)转换以string类型为参数的构造函数。



(2)构造函数(用于直接或复制初始化 )的使用模式。

事实上,我们说这些东西特殊,关键是他们时候的时候特殊,两种构造函数(对应两种初始化方式)都有显示和隐式的构造方法。

对于直接初始化,我们知道显示的方法,就是使用类名加上参数(其实就是在调用构造函数),隐式的方法,就是在一个需要该类对象的地方出现了其他的数据类型,于是系统会自动调用对应函数(这个应该在编译的时候应该调用了)因为这个时候可以检测出错误来。

对于复制初始化,最显示的调用手段就是使用“=”符号(这个时候应该成为复制初始化符号)。那么还有许多地方是隐式的调用。如参数传递时,函数返回时,初始化容器时!

1)对于参数传递:我们知道除非是引用参数,否则就是一个使用上层对象复制初始化函数参数的过程。

2)对于函数返回值:我们知道除非是引用返回,否则在return的那个语句就是使用函数内的对象,复制初始化一个上层对象(通常是临时的,然后马上有被用于)

3)在某些容器初始化的过程中如:
 
  vect<string> svec(5);


   这里的过程就是,先使用string默认构造出一个实例对象,然后使用这个对象,复制初始化其它的元素。这个过程是容器的实现细节,其实从外面看,可以理解为直接初始化。
4)数组初始化,有时候使用这样的语法:

  Sales_item primer_eds[]={  string("1231231"),
                                              string("3123123")
                                           }


 可知这个过程,就是一个先调用直接初始化生成string,然后继续隐式调用直接初始化生成Sales_item。最后使用复制初始化,给那个数组的各个元素初始化。

从上面两个关于容器(包括数组)的初始化过程可以看出,他们与普通的类(也是包含许多的元素对象)的不同了 !

(3)组装复制构造函数。

对,我们现在学习了,默认构造函数(没有参数的,可能是系统定义,可能是用户定义,系统只有在没有任何构造函数的情况下定义默认构造函数),而系统定义的默认构造函数就叫做组装默认构造函数,还有一种特殊的构造函数——类型转换构造函数(其实并不特殊);现在学习了组装复制构造函数(只要用户没有主动构造一个复制构造函数(使用类型引用做参数),系统就会自行组装);就算只定义了复制构造函数,系统也不会自动组装默认构造函数,所以,如果你定义了复制构造函数,那么一定要定义普通构造函数(最好有默认构造函数)。要不然,就没有构造函数了。

想到这里,我们发现不管什么什么类型的构造函数,功能都是实例并初始化对象,可能复制构造函数与普通构造函数的过程有些不同(其实就是使用的方法和领域不同),但是他们仍然是平等的。所以只有一个默认构造函数,并且只有当没有任何自定一构造函数的时候,系统才会有组装构造函数;而复制构造函数,是一定有的(不管在什么情况)。

其实复制构造函数的本质依然是构造函数,它的功能就是使用那个已知的对象中的元素,“逐个”的赋值给那个需要初始化的对象。所以,你可以把组装复制构造函数,想象成一个带有所有对象元素(顺序也一至)的初始化列表的构造函数。

与普通构造函数一样,涉及到对某个元素的初始化时,对于内建类型,直接使用copy的方法,对于类类型,使用定义复制构建函数。如果没有定义复制构建函数,就使用组装的,毕竟复制构建函数的参数是一定的,所以基本不存在无法复制的元素的可能。 但是直接构造函数就有可能出现,子元素没有默认构造函数的情况,而不能进行构造,并且直接构造的时内建类型也有可能不初始化(依编译器而定)。

另外一个要注意的是,虽然我们没有办法进行复制初始化数组(这就是为什么数组没有办法作为参数传递,或则作为返回值返回,或者定义的时候用一个数组来复制初始化另外一个数组),但是当数组在某个其他类型的里面的是后,这个时候如果发生了复制初始化,作为元素的数组会也被复制初始化,但是,是通过逐个复制元素的方法。
(4)自定义复制构造函数

class Foo{
public:
   Foo();   //默认构造函数
   Foo(const Foo&);   //复制构造函数 
}


其中,const可以不写(但通常建议这么做),由于复制的作用要用到传递参数、返回值,这些都是隐式的调用,所以一定不能将其声明为explicit。所以可以知道explicit的作用就是承认在可能的情况下,系统默认在需要使用该函数的情况下,能不能自动使用。

从前面我们说可以将组装复制构造函数用相应的带有完全初始化列表的构造函数来代替,我们可以发现,复制构造函数要实现的功能基本稳定,所以通常组装复制构造函数基本可以满足要求。

所以我们经常不怎么自己定义复制构造函数,但是有些时候程序实现要求我们必须自定义构造函数,这个时候我们就表明了,构建复制构造函数的困难之处,不在于语法 ,它与普通的构造函数是一样的;关键是在,构建这个东西的用途,当用途明确后,其他就简单了。

有些时候,例如
1)对象成员是一个指向某个资源的指针(用户本意不想只是复制指针,那表明没有复制指针指向的对象),
2)或者该类型规定每新建一个对象需要做一些动作,那么这个时候就需要自定义复制构造函数
(注意哦!与普通构造函数一样,构造函数理论上的功能包括空间分配、元素初始化,以及相关处理,那个复制初始化符号“=”左右应该看成一个整体。)
3)或者该类型的每个对象都富有一个唯一ID成员的机制

(5)如何阻止类的复制初始化功能

1)我们知道,我们使用explicity可以声明,该复制构造函数不能被隐式使用,于是在参数、返回值的那些地方都不能用,但是如何让普通的复制初始化也不用呢? 那就是声明为private。我们说过。构造函数的特殊还在于,它是直接被外层使用的,不需要套一个什么类的帽子(因为它就是类名),所以如果申明为private那么就不能使用了,这就是为什么大部分的构造函数都被申明为public了。

 

C++直接初始化与复制初始化的区别深入解析 主要介绍了C++直接初始化与复制初始化的区别深入解析,是很多C++初学者需要深入了解的重要概念,需要的朋友可以参考下 立即下载

相关推荐

STM32低功耗模式下ADC采样抖动的5个隐藏陷阱及解决方案(实测避坑)

本文深入探讨了STM32低功耗模式下ADC采样抖动的5个常见陷阱及解决方案,包括多通道采样电压跃迁、外设开关信号稳定、低功耗模式与ADC时钟同步、输入阻抗失配以及基准电压稳定性问题。通过实测数据和优化代码示例,帮助工程师有效规避ADC采样数据抖动问题,提升物联网设备的测量精度和稳定性。

weixin_30316097的博客 382

C++中直接初始化和拷贝初始化

一、Primer中的说法 首先我们来看看经典是怎么说的: “当用于类类型对象时,初始化的复制形式和直接形式有所不同:直接初始化直接调用与实参匹配的构造函数,复制初始化总是调用复制构造函数。复制初始化首先使用指定构造函数创建一个临时对象,然后用复制构造函数将那个临时对象复制到正在创建的对象” 还有一段这样说, “通常直接初始化和复制初始化仅在低级别优化上存在差异,然而,对于不支持复制的类型,或者使用非explicit构造函数的时候,它们有本质区别: ifstream file1("filename"

qq_38915078的博客 856

告别付费!手把手教你用DataV.GeoAtlas获取全国街道级GeoJSON数据(附完整避坑指南)

本文详细介绍了如何免费使用阿里云DataV.GeoAtlas工具获取全国街道级GeoJSON数据。通过可视化选取、格式转换、数据校验等步骤,提供了一套完整的避坑指南和工作流,帮助前端和可视化开发者高效解决高精度地图数据获取难题,节省成本并提升开发效率。

weixin_29085865的博客 901

[C++] - 中的复制初始化(copy initialization)

过去在学习C++中类对象创建时,对constructor关注的很多,天真地认为了解了constructor,copy constructor,copy assignment就对类对象的创建理解了,今天遇到的一个看似不起眼的问题让我认识了还有copy initialization这么个东东,通过网上查阅揭开了copy initialization写神秘面纱,下面讲一下自己的一点理解。 首先看一下问...

浮生的博客 1616

COLMAP性能优化实战:如何用GPU加速和并行计算让重建速度提升300%

本文详细介绍了如何通过GPU加速、并行计算和参数调优显著提升COLMAP的三维重建效率。从硬件资源分配到计算流程优化,再到大型数据集的分块处理策略,全面解析了将重建速度提升300%以上的实用技巧,特别适合处理无人机航拍和室内扫描等大规模三维重建项目。

weixin_29098391的博客 202

R语言中如何获取前向选择(forward selection)选出的变量

前向选择是一种常用的特征选择方法,可以在给定一个预测模型的情况下,逐步添加变量来确定最佳的预测模型。在R语言中,可以使用适当的函数和库来执行前向选择,并获取选出的变量。以下是一个详细的步骤,展示了如何使用R语言执行前向选择并获得选出的变量。通过按照上述步骤,你可以使用R语言执行前向选择,并获取选出的变量。记住,前向选择是一种特征选择方法,可以根据不同的评估指标选择最佳的预测模型。接下来,准备用于前向选择的数据。使用"summary"函数查看前向选择的摘要,并使用"which"函数获取被选中的变量。

WangWEel的博客 924

C++-直接初始化和拷贝初始化

文章目录初始化拷贝初始化直接初始化构造函数与拷贝构造函数拷贝初始化与拷贝构造函数例子 初始化 变量的初始化有两种方式: 直接初始化(direct initialization) 拷贝初始化(copy initialization) 拷贝初始化 如果使用等号(=)初始化一个变量,则执行的是拷贝初始化。 直接初始化 不使用等号的,则是直接初始化。 构造函数与拷贝构造函数 如果一个构造函数的第一个参数是自身类型的引用,且任何额外参数都有默认值,则此构造函数是拷贝构造函数 拷贝初始化与拷贝构造函数 拷贝初始化依

mrbone11的博客 1182

通用抓取算法AnyGrasp(Graspnet)——本地部署并测试自定义输入数据

背景:GraspNet在数据采集方面,首先将相机固定到机械臂末端,对同一个场景拍摄256个不同的角度,同时场景中的每个物体都会提前采集好3D模型,之后将其投射到仿真环境中,在仿真环境中,对抓取位姿进行打标签,如此完成数据的采集。在运行官方的测试示例时,使用的是路径下的输入数据,可以分析下。color.png(输入):rgb图像(输出):输出的生成抓取位姿的图像depth.png(输入):和当前rgb图像对应的深度图像(保存格式是单通道uint16)meta.mat。

boss-dog 1330

【C++】【基础知识】直接初始化与拷贝初始化

文章来源,建议看原文:直接初始化与拷贝(复制)初始化 认识这两种初始化有助于我们加深对语言的理解,可以更好的优化代码~ 我们常见的几种初始化的形式: string str1 = "first"; //拷贝初始化,编译器允许把这句话改写为string str(“first”),但是string类必须有public的拷贝(移动)构造函数 string str2(10,'a'); //直接初始化 string str3(str2); //直接初始化 string str4 =

YJYS_ZHX的博客 1306

9.6华为OD机试真题 新系统 - 仓储货物有序出库 (Java/Py/C/C++/Js/Go)

9.6华为OD机试真题 新系统 - 仓储货物有序出库 (Java/Py/C/C++/Js/Go)

算法大师! 1201

linux安装配置Mysql详细步骤

下载Mysql rpm包 官网下载:https://dev.mysql.com/downloads/mysql/ 如果你到了这里,本地应该有了如下四个rpm包: mysql-community-client-5.7.26-1.el6.x86_64.rpm mysql-community-common-5.7.26-1.el6.x86_64.rpm mysql-community-libs-5...

🏆 前端领域优质创作者 7万+

C++ 直接初始化和复制初始化

在C++里,对象初始化是一个非常重要但又容易令人混淆的问题。这里是自己的一些总结。 一。初始化与赋值的含义: 初始化:包括创建(或说定义)对象并且赋给初值。(如果一个对象只被创建而没有被初始化,则该变量只能用于被赋值)。 赋值: 擦除对象的当前值并用新值代替。 二。内置类型: (一)直接初始化: 1.空初始化:即无参数无括号形式 如int i,new int,new int[

sead+ 1322

uniapp ios原生插件开发 (framework,cocoapods)

已知UniApp的插件开发方式有两种, 第一种 Xcode Framework的方式,这种方式是官方指定的方式。 这种方式的优点就是简单直接, 但也有不足,比如当插件需要引入一些三方库时,操作起来就不是那么方便。 而使用Cocoapods则可以很方便的引入三方库。 接下来,本文探索使用Cocoapods的方式来进行UniApp插件开发。

Rey的技术博客 9824

C++中的复制初始化与直接初始化

C++ Primer里说过,在C++中,初始化不等于赋值,初始化是指创建变量并给变量赋初值,而赋值是指擦除变量的当前值并用新值替换。C++中有两种初始化方法,直接初始化和复制初始化。直接初始化是指使用 Object obj(patamer)这样的语句,Object可以是内置类型或者用户自定义的类类型;而复制初始化是指Object obj = obj1。 1)内置类型的初始化    以int型为

miludeyingxiong的专栏 1015

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

C++直接初始化与复制初始化<一>

现在正式对C++中对象建立和初始化做一个总结。 (1)复制初始化的基本原理 我们知道,对象在内存中的直接表象是在内存中占有一个一定大小的空间。分配空间是建立对象的第一步。但是刚刚分配的空间就像一个没有开垦的荒田,或者是前面对象占有之后留下来的残余,从理论上讲,由于不管是什么大家都是0101,所以就算没有初始化也是有值的,只是这个值你是不能正确使用的。所以建立对象的关键在于如何对该对象所占有

zou_J_L专栏 675

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

C++类的直接初始化和复制初始化举例

(1)对于一般的内建类型,这两种初始化基本上没有区别。           int a(5);//直接初始化           int a=5;//复制初始化           int a=int (5);//直接初始化 (2)当用于类类型对象时,初始化的复制形式和直接形式有所不同:          直接初始化直接调用与实参匹配的构造函数,复制初始化总是调用复制构造函数。

shengwusuoxi的专栏 1283

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

c++中的直接初始化与复制初始化

按照C++   Primer第四版中文版13.1节中的说法: 1.对象的定义 回忆一下,C++支持两种初始化形式(2.3.3节):直接初始化和复制初始化。复制初始化使用=符号,而直接初始化将初始化式放在圆括号中。 当用于类类型对象时,初始化的复制形式和直接形式有所不同:直接初始化直接调用与实参匹配的构造函数,复制初始化总是调用复制构造函数。复制初始化首先使用指定构造函数创建一个临时对象(7.

NicolasHe的专栏 2320

C++的直接初始化与复制初始化的区别

本文转载自:负一的平方根 https://sqrt-1.me/?p=241          修改了部分地方 C++中的直接初始化指的是直接调用类的构造函数进行初始化,如下例如 string a; //调用默认构造函数 string a("hello"); //调用参数为const char *类型的构造函数 string b(a); //调用拷贝构造函数 复制初始化指的是用“=”号来初始...

qq936836的专栏 2369

C++中直接初始化与复制初始化

C++中直接初始化与复制初始化是很多初学者容易混淆的概念,本文就以实例形式讲述二者之间的区别。供大家参考之用。具体分析如下: 一、Primer中的说法 首先我们现来看看经典是怎么说的: “当用于类类型对象时,初始化的复制形式和直接形式有所不同:直接初始化直接调用与实参匹配的构造函数,复制初始化总是调用复制构造函数。复制初始化首先使用指定构造函数创建一个临时对象,然后用复制构造函数将那个临时对

BaldwinGO的博客 279

C++直接初始化和复制初始化1

这篇文章主要介绍了C++直接初始化与复制初始化的区别深入解析,是很多C++初学者需要深入了解的重要概念,需要的朋友可以参考下 C++中直接初始化与复制初始化是很多初学者容易混淆的概念,本文就以实例形式讲述二者之间的区别。供大家参考之用。具体分析如下: 一、Primer中的说法 首先我们现来看看经典是怎么说的: “当用于类类型对象时,初始化的复制形式和直接形式有所不同:直接...

weixin_30687811的博客 85
上一篇: 指向函数的指针
下一篇: 数据结构之排序算法--C#实现
wait009alone
博客等级 码龄15年 2粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值