8.6.4 关于构造函数和复制构造函数

    复制构造函数可以看成是一种特殊的构造函数,这里暂时区分为“复制构造函数”和“普通构造函数”,因此,它们也支持初始化表达式。

    创建对象时,只有一个构造函数会被系统自动调用,具体调用哪个取决于创建对象时的参数。C++对编译器何时提供默认构造函数和默认复制构造函数有着独特的规定,如表8.1所示。

    8.6.4 关于构造函数和复制构造函数 - 图1

    不管是普通构造函数还是复制构造函数,构造函数是由系统自动调用的,程序中不能直接调用构造函数。

    下面来看一个具有实质性的问题:普通构造函数和复制构造函数到底做了什么?主要体现在以下几个步骤中。

    (1)在创建对象时,C++根据传递的参数选择一个合适的构造函数,如果没有匹配的构造函数,编译器会报错,否则执行该构造函数。

    (2)进入构造函数后,首先就是为成员变量开辟内存空间,对普通变量(如前面介绍的int、double、char、指针等)来说,能够直接完成空间的开辟,假如数据成员也是一个类的对象,情况稍显复杂,此时要检查成员初始化表,根据其中传递给对象成员的参数检查是否有可用的构造函数(在对象成员的类中定义的构造函数),由对象成员的构造函数为其开辟内存空间,如果成员初始化表中没有为该对象成员传递参数,则该对象的无参构造函数或所有参数都由默认值的构造函数构成,也可能是系统为对象所在类提供的默认构造函数被调用,用以开辟对象空间。

    (3)按照类中定义的成员变量顺序,执行成员初始化表。应注意的是并非按成员初始化表的语句先后执行成员初始化,其只取决于类中定义的成员顺序。如果没有成员初始化表,本步骤跳过,直接到步骤4。

    (4)执行构造函数体,完成其他操作。

    由此看来,默认的构造函数只完成了其中一个功能,那就是步骤2,为成员变量开辟空间,需要说明的是如果类中有对象成员,那么该对象所在的类中必须定义了无参构造函数或所有参数都有默认值的构造参数,或者干脆由系统提供的构造参数,其他情况下,均不合法,对象成员所占内存空间无法开辟,编译器报错。

    缺省的复制构造函数似乎没有这么麻烦,编译器根据源对象为目的对象开辟空间,并将源对象中的成员按“内存单元复制”的方式复制到目的对象中,经过这个操作后,源对象和目的对象除了地址不同外,各个成员的取值都是相同的。