(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++直接初始化和复制初始化相关推荐

  1. C++直接初始化与复制初始化的区别深入解析

    首先:这是原文地址,这个哥们的文章解决了我的问题.谢谢这个哥们了.下面把原文地址放在这里: https://www.jb51.net/article/54773.htm C++中直接初始化与复制初始化 ...

  2. 复制初始化和直接初始化

    string str("12345"); string str = "12345"; 在写代码时忽然想到这个两个有啥区别呢,其实这个还是c++基础薄弱的原因 于 ...

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

    过去在学习C++中类对象创建时,对constructor关注的很多,天真地认为了解了constructor,copy constructor,copy assignment就对类对象的创建理解了,今天 ...

  4. Spark源码剖析 - SparkContext的初始化(八)_初始化管理器BlockManager

    8.初始化管理器BlockManager 无论是Spark的初始化阶段还是任务提交.执行阶段,始终离不开存储体系.Spark为了避免Hadoop读写磁盘的I/O操作成为性能瓶颈,优先将配置信息.计算结 ...

  5. 就地初始化与列表初始化

    1.就地初始化   在 C++11 之前,只能对结构体或类的静态常量成员就地初始化,其他的不行. class C { private:static const int a=10; // yesint ...

  6. 标准K-means算法的缺陷、K-mean++初始化算法、初始化算法步骤、Kmeans++算法实现

    标准K-means算法的缺陷.K-mean++初始化算法.初始化算法步骤.Kmeans++算法实现 目录 标准K-means算法的缺陷.K-mean&

  7. 为什么权重初始化要非对称?为什么权重初始化不能全为0?为什么初始化值不能太大或者太小?介绍下He初始化以及Xavier初始化?

    为什么权重初始化要非对称?为什么权重初始化不能全为0?为什么初始化值不能太大或者太小?介绍下He初始化以及Xavier初始化? 目录

  8. Java静态初始化,实例初始化以及构造方法

    静态初始化:是指执行静态初始化块里面的内容. 实例初始化:是指执行实例初始化块里面的内容. 构造方法:一个名称跟类的名称一样的方法,特殊在于不带返回值. 1.一个对象第一次被创建时,先要加载该对象所属 ...

  9. 初始化全局变量实例说明C语言中初始化和未初始化的全局变量所在不同的段

    本文是一篇关于初始化全局变量的帖子 实例说明C语言中初始化和未初始化的全局变量地点不同的段 一个程序: Makefile: objs := bss.oall: bss bss: $(objs)gcc ...

最新文章

  1. 超级细分插件_草图大师必装插件
  2. 使用JAVA开发微信公众平台(一)——环境搭建与开发接入
  3. nyoj 61 传纸条(一) (双线动归)nyoj 探寻宝藏
  4. ggplot2箱式图两两比较_第十九章_使用ggplot2进行高级绘图
  5. mysql on后加and_mysql加入ON和AND to laravel eloquent
  6. android banner动画框架,Android Studio Banner轮播图使用
  7. 算法学习(二)快速排序(下)
  8. web页面防盗链功能使用--request.getHeader(Referer)
  9. ios软件商店上架老被打回_一款APP上架苹果应用商店的流程,费用是多少?
  10. 【玩转开源】BananaPi R2——移植RPi.GPIO 到 R2
  11. Rust: CTP的rust版本如何手工封装
  12. 自动优化Windows Xp批处理文件
  13. Linux大棚版redis入门教程(推荐)
  14. TKMybatis的使用大全和例子(example、Criteria、and、or)
  15. 爬虫-3-requests和代理
  16. MFC之画圆弧 任意三点绘制圆弧求弧长
  17. 扫盲区分IaaS和PaaS
  18. CVPR2019|最新更新论文~持续更新|CVPR2019百度云下载
  19. postgresql + postgis 离线安装
  20. Java实现 LeetCode 91 解码方法

热门文章

  1. Untiy AVpro
  2. 计算机课word反思,教学反思Word文档
  3. 绝地求生6月23号服务器维护到几点,绝地求生6月23日更新到几点 绝地求生6月23日更新内容介绍...
  4. RS232、RS485及RS422有什么区别
  5. 爬取 48048 条评论,解读 9.3 分的「毒液」是否值得一看?
  6. ssm毕设项目基于的少儿编程学习系统2lsiy(java+VUE+Mybatis+Maven+Mysql+sprnig)
  7. php 00截断,文件上传之\00截断与文件包含之%00截断 文件包含漏洞详解 – jinglingshu的博客...
  8. 2021年最新最全Flink系列教程_Flink快速入门(概述,安装部署)(一)(JianYi收藏)
  9. 牛客网 Cutting Bamboos 【主席树+二分】
  10. 用Java SE 6.0实现高质量桌面集成开发 (转)