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

C++ 笔记1——explicit关键字、构造函数与对象初始化 创建:2018/4/4;最近更新:2018/4/4写在前面    这几篇笔记不是那种讲解C++基础概念的入门级教程,也不是纷繁复杂、面面俱到的专家级教材。因为这两种资料在网络上或者是出版的书籍上已经够多了。在这里,我主要想记录自己在学习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++初学者需要深入了解的重要概念,需要的朋友可以参考下 立即下载

相关推荐

带挂牵引车前向运动模型推导及仿真实现

牵引车-半挂车的车辆结构与普通的车辆相比增加了一个半挂车,它们之间通过鞍座相连接,为了分析半挂牵引车运动过程中的位姿和状态,本文将基于车辆的机械结构建立对应的运动学模型,该模型基于以下假设: 车辆行驶过程中,道路平坦且无凸凹; 车辆低速行驶,且运行过程中车身无侧倾和俯仰运动; 车辆行驶过程中,轮胎无形变,无侧向滑动,且无侧向力; 牵引车和半挂车均满足阿克曼转向几何原理; 牵引车与半挂车不会发现折叠。

jianmo的博客 3181

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

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

qq_38915078的博客 856

CGNS快速入门到实战(二):VS配置调用CGNS静态链接库

CGNS快速入门到实战这一系列分成三篇文章展开叙述,具体有:(一)CGNS静态链接库编译;(二)VS配置调用CGNS静态链接库;(三)CGNS文件及案例展示。本篇文章重点讲述VS配置调用CGNS静态链接库。

ahang_99的博客 2616

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

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

浮生的博客 1616

ubuntu安装XXX包时出现(= 20.0.8-0ubuntu1~18.04.1) but it is not going to be installed

安装mujoco_py时,最后一步尝试 import mujoco_py 时出现报错 esashim.c:1:10: fatal error: GL/osmesa.h: No such file or directory 1 | #include <GL/osmesa.h> | ^~~~~~~~~~~~~ compilation terminated. 在https://github.com/openai/mujoco-py#ubuntu-ins

dealexce的博客 1793

SAP ERPsim生产拓展实验报告

ERP课的实验和实践,也是SAP竞赛玩的东西,除了界面不华丽外很像游戏而且是团队型的pvp大乱斗

m0_67262022的博客 2020

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

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

mrbone11的博客 1182

Mac新手必看:nvm安装全攻略(含常见错误解决方案)

本文为Mac开发者提供nvm安装与使用全攻略,涵盖环境准备、安装步骤、Shell配置优化及常见错误解决方案。详细讲解如何利用nvm管理多Node版本,提升开发效率,特别针对国内用户提供网络问题解决技巧,是Mac新手必备的Node版本管理指南。

weixin_28839699的博客 1602

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

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

sead+ 1321

CAN开发笔记(TI开发者推荐笔记)

查阅了很多资料没有查阅到关于5728芯片CAN模块寄存器的介绍,希望通过本文能给做CAN驱动的后来者有一点参考意义,我也是刚接触CAN模块有些不足请各位多多指正。 由下图所示是CAN模块初始化流程图 首先要开始初始化,设置CAN位时间,然后配置message objects, 完成初始化。 1.开始初始化 首先要控制DCAN_CTL 寄存器,该寄存器是CAN模块的总控制器,很多配置通过...

weixin_44316996的博客 3561

【AI应用实战-OpenCode】OpenCode安装部署(一)

OpenCode是一款2026年流行的开源AI编程工具,兼具轻量代码编辑器和智能编码代理功能。其核心优势包括:完全免费开源(MIT协议)、全平台兼容、支持75+大模型(含本地部署)、内置完整编程功能链(代码补全/Git集成/AI调试等),且所有数据本地存储确保隐私安全。相比Copilot等商业工具,OpenCode提供更自由的模型选择和零门槛使用体验。安装要求Windows10+/macOS12+/Linux主流发行版,仅需200MB空间和4G内存。该工具完美兼容VSCode生态,支持终端/桌面/IDE三种

2421

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

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

miludeyingxiong的专栏 1015

OpenClaw 多机器人多 Agent 模式:打造你的 AI 助手团队

OpenClaw多Agent模式为企业提供高效的AI助手团队解决方案。通过创建4个独立的飞书机器人(主助理、内容创作、技术开发、AI资讯),每个连接专属Gateway和Agent模型(如Claude Opus/Sonnet、Gemini 2.5),实现专业分工。相比单Agent模式,多Gateway架构具有配置清晰、互不干扰、无需手动切换等优势。系统采用Profile隔离机制,各Agent拥有独立配置和端口。部署过程包括创建机器人应用、配置Agent、运行自动化脚本等步骤,支持私聊或群组@使用。日常提供状态

Maynor的博客 5096

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

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

zou_J_L专栏 675

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

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

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

shengwusuoxi的专栏 1283

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

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

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

NicolasHe的专栏 2320

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

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

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

qq936836的专栏 2368

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

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

BaldwinGO的博客 279

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

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

weixin_30687811的博客 85

c++直接初始化和复制初始化 理解

直接初始化拷贝初始化的区别分析

Nichalos_Song的博客 1864
上一篇: Linux驱动阻塞的实现
下一篇: Android 智能指针
计算机与认知
博客等级 码龄14年 31粉丝 19原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值