深度分析C++默认构造函数拷贝构造函数
Posted tab_tab_tab
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深度分析C++默认构造函数拷贝构造函数相关的知识,希望对你有一定的参考价值。
对于C++初学者来说,时常不难看到他们说:
1.任何class如果没有定义默认构造函数,那么就会由编译器来合成一个出来。
2.编译器合成来的构造函数会明确确定里面所有成员的值。(比如int类型成员会初始化成0)
呃,这当然是一部分C++新手的一厢情愿吧、其实C++里面对于构造函数的诞生与否是取决于编译器是否需要必须要为其产生构造函数。。。或者说是有点类似被迫不得已时候,编译器才会合成构造函数。这是第一点。
第二点,只有编译器迫不得已时候,才会帮你初始化某些成员,而绝对不是所有成员都进行初始化。
无论如何也好吧,请记住这个词:迫不得已时候。
举个例子吧
class Aprivate:int mdata;
就是这样的类,假设没有任何构造函数,那么当我们声明一个对象 A x;时候,会不会产生构造函数?会不会有mdata的0初始化发生?
答案是:没有任何构造函数被合成,就算假设有,好吧,我加粗了假设,再次强调是假设有,也不会初始化成0。还记得我们刚刚说的那个词语么?迫不得已,我们可以这样想,C语言里面 A x;这样子的结构体也是可行的,那么我们就没有把编译器逼到迫不得已的地步,或者想《深度探索C++对象模型》这本神书说的一样,这是程序员的职责去写构造函数,去初始化。这个和编译器没有半毛关系。。
那么,什么事情才算是迫不得已让编译器合成构造函数呢?构造函数的合成是类似什么都不做?还是另有一番洞天? = = !
1.成员对象具有默认构造函数,这时候编译器就无法再去偷懒了,生活已经把懒惰的它强迫到要去合成代码的地步了,怎么说呢?或者我们可以这样想吧。假设成员对象里面有一个蛋疼的功能是申请堆资源。假设编译器不帮这个类合成构造函数,那么悲催的类中某一个成员对象生来就没有申请到堆资源。。。这样就很莫名其妙的,对吗?
呃,问题又来了,所谓的合成代码是值什么合成呢?它是怎么合成的呢?假设有1000个cpp文件,每个文件都有这个没有构造函数的类的定义,都要用到这个定义的类,那么编译器是如何分别给1000个文件去合成这个类的构造函数呢?呃,编译器是这样做的,如果文件中存在着类对象的定义,那么就必须要付出合成代码的代价。。。这时候采取的合成代码是尽量使用 inline方式合成。要是一些莫名其妙的代码,真的是无法用inline合成了,就采取static合成,呃,其实inline也好,static也好,都是为了避免产生多个全局的符号。。。你懂得,1000个全局符号,这个链接器估计也得受不了吧。。。目测得符号抛出符号重定义错误,毕竟是1000个强符号啊…..
呃,问题又来了。。构造函数将会扩充成什么样子?或者这样说吧。。。它初始化一些什么东西?偷偷帮什么成员进行了默认构造函数的调动。答案是:对内置类型,像什么int double 鸟都不鸟他们,噢,那些没有构造函数的类,看起来有点像C语言的结构体吧。。。C语言都不鸟它,那么C’++干嘛要鸟他?对吧。。。所以对于带有构造函数的成员对象,才会被构造函数偷偷的初始化,即使偷懒的程序员没有初始化他们!!编译器也得做!具体原因见上面再上面几行加粗的字体。。。好好读读。编译器是懒惰的,迫不得已时候才会对其进行改变。。。。
呃。。。这是最后一个问题了吧。。。构造函数函数对成员的初始化顺序是和什么有关的?A 构造函数参数列表?B 成员对象声明次序?
答案是B。。。又到了要说为什么然后解释的时候。。。简单的一个反证法就可以想出来了,假设是A,那么对于一些不带构造函数参数列表的类,是不是就不对带有构造函数的成员对象初始化?这不科学吧???
2.带有构造函数的基类。。道理有点类似啊,要是派生类继承了基类,基类再构造函数里面申请堆资源。。。那么作为派生类,是否应该把应该属于你的资源找回来????或者举例子说吧,按照人的语言,公有继承是表达 “是”的意思,假设老师继承了人,人有吃饭的属性,在构造函数里实现了,然后老师继承了人,但是没有调动构造函数,老师变成了只会领取工资不会吃饭的人。。。。— —!
3.带有虚指针的类
这个怎么说呢,也是反证法!!!!!!假设编译器傻不拉几的把这个类忽略了,不再为它合成构造函数,那么会有什么后果?毫无疑问!!!!vfptr那些东东全部都是0xCCCCCCCC(栈)或者0xCDCDCDCD(堆)。。。。编译器意思说,愚蠢的程序员,你自己来重置虚表吧!!!然后这个编译器就被程序员输入 kill -9杀掉了。。。好吧!!!重点来了!
两个扩张操作会在编译期间完成!
a.编译器为了支持基类指针指向派生类对象,实现多态,必须要在编译期把虚表这些都搞出来。。。地址填好
b.噢,每一个类对象里面,都要给他们塞进一个指针,让他们指向那个虚表。。。
记住了,我们编译器为了不被程序员kill掉做了太多太多的东西了。。。真是可怜的编译器
4.带有虚基类的类,呃。虚继承意思是共享继承的意思。。。因为对应菱形继承结构可能会存在C里面有两个X的类。。。呃,要是再往下数据冗余会更加严重。。。这时候就引入了虚继承这个概念了
— — !长话短说!虚继承破坏了纯C的那个存储结构,如果编译器不按照一定的只能去恢复构造功能,那么就将会很诧异了
以上是关于深度分析C++默认构造函数拷贝构造函数的主要内容,如果未能解决你的问题,请参考以下文章