[c++03]为啥需要拷贝构造?
Posted AIplusX
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[c++03]为啥需要拷贝构造?相关的知识,希望对你有一定的参考价值。
写在前面
今天咱们主要来探究一下,我们为啥需要拷贝构造这个东西,以及拷贝构造的一些基本语法。
正文
在这里呢,我先给一段测试程序,探究一下没有拷贝构造对于类到底会有什么影响,这段程序我也是参考了浙江大学的翁恺老师教授C++课程时上课的例程,感谢翁恺老师的无私奉献!
这段程序看起来比较复杂,让我来慢慢分析一下。首先我定义了一个static
的变量i
,为什么要是static
的呢?因为我需要i
是全文件可见的。
然后我构造了一个A
类,在A
类的构造函数里面,我将全局的i
进行自加1,并且输出一些相关信息,在A
类的析构函数里面,我将全局的i
进行自减1,并且输出一些相关信息。为什么要这么做呢,其实就是为了记录A
类生成对象的时候,构造函数和析构函数被调用的情况。
那么在A
类里面还有print_i()
这个函数,也就是为了打印调用函数时刻的i
值。
那么在这个测试程序里面发生了几次对象的实例化呢?
仔细数数一共是3次,a, a2
和f()
函数的形参a_t
,当调用f()
函数的时候,f()
函数会根据实参a
来构造出一个形参a_t
来。
那么我们来看看程序的结果输出是什么:
正常来说,当最后程序结束的时候,i
的数值应该是0,但是结果确实-2,说明此时程序肯定是有了问题的。
为了说明这个问题,我需要一些先备知识,那就是关于c++的=
号的,在c++里面将对象a
赋给b
,也就是做对象的a=b
的时候,这个=
时如何起作用呢?那就需要知道c++里面的运算符重载相关知识了,c++里面的运算符是可以重载成用户需要的功能的,也就是说=
实现的功能可以是将两边的变量或者常量进行相减(当然,我非常不建议这样做)。好了,言归正传,在这个测试程序里,我们并没有重载=
号,所以如果用了=
号的时候,程序应用的就是默认的=
功能。
那么如何进行对象的默认赋值呢?也就是说对象的a=b
到底发生了什么呢?其实这个发生的就是拷贝工作,不过这个拷贝不是按字节进行拷贝的,而是按照成员进行拷贝的,不是bitwise的拷贝,而是memberwise的拷贝。所以对象的a=b
的时候,是将对象b
里面放的成员变量按照成员拷贝到对象a
里面的。
好了,回到了我们的测试程序,首先我们构造出了a
这个对象,此时i=1
,这没有问题,接下来我调用了f()
,此时就发生了一次对象的拷贝,因为将实参对象a
拷贝成了形参a_t
,发生了memberwise的拷贝,但是此时i
没有进行自加,这说明构造函数没有被调用,这就很奇怪了,导致函数结束的时候调用了对象的析构函数,i
进行了自减,导致i
变成了0。
接下来A a2=f(a);
又发生了一次memberwise的拷贝,此时构造函数又没有被调用,因为此时的i
是0。最后,a
和a2
都被析构了,导致i
进行了2次自减操作从而变成了-2。
经过我们分析,问题就很明白了,当对象发生memberwise的拷贝的时候并不会调用默认构造函数,也就是default constructor,这是很危险的,一个对象做出来的时候没有被初始化过是非常危险的,因此我们要解决它,解决方式就是拷贝构造函数。拷贝构造函数的作用就是用已有的对象来初始化一个新的同类对象,也就是说做对象的a=b
的时候,拷贝构造函数是会被调用的,可以理解成将对象b
做为参数来实例化类A
得到对象a
,看下面这段例程感受一下:
结果如下:
可以看到i
最后变成了0,说明拷贝构造函数起作用了。
所以,为了保证程序的正常运行,以后写类的时候,记得要写一个拷贝构造函数。
以上是关于[c++03]为啥需要拷贝构造?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我的 C 代码片段不起作用?简化版可以。为 unsigned long long 传递不带 VA_ARGS 的 args