构造函数/复制构造函数/析构函数/赋值操作符这几个概念是C++中一个类里面的几个基本函数,作为初学者的我对这几个概念比较生疏,对其用法也有些疑问,下面对这几个基本的函数进行总结。这里主要说明他们的含义以及何时需要用户自己定义(和默认的有啥区别)。
构造函数:
构造函数是特殊的成员函数,只要创建类类型的新对象,都要执行构造函数。构造函数的工作是保证每个对象的数据成员具有合适的初始值。构造函数需要注意几点,一是构造函数可以被重载,由实参决定使用哪个构造函数,二是对于const对象,const构造函数是不必要的。创建类类型的const对象时,运行一个普通构造函数来初始化该const对象。构造函数的工作是初始化对象。不管对象是否为const,都用一个构造函数来初始化该对象。(C++ Primer)
一般情况下,在用户需要对对象初始化进行控制的时候,会定义自己的构造函数,这个时候,编译器不会再生成默认构造函数。这条规则的根据是,如果一个类在某种情况下需要控制对象初始化,则该类很可能在所有情况下都需要控制。(C++ Primer)
除了编译器默认的构造函数,通常情况下类定义一个默认构造函数,用户可以使用这个默认的构造函数进行初始化。
复制构造函数:
复制构造函数主要用于控制复制某类型的对象时会发生什么,它是一种特殊的构造函数,具有单个形参,该形参是该类类型的引用。当定义一个新对象并用一个同类型的对象对它进行初始化时,将显示使用复制构造函数。当将该类型的对象传递给函数或返回该类型的对象时,将隐式地调用复制构造函数。
同构造函数一样,复制构造函数有编译器合成的复制构造函数,也可以定义自己的复制构造函数。何时需要定义自己的复制构造函数是一个难点。一般而言,只包含类类型成员或内置类型(不是指针类型)成员的类,无须显式地定义复制构造函数,也可以复制。
有些类必须对复制对象时发生的事情加以控制。这样的类经常有一个数据成员是指针,或者有成员表示在类中需要分配资源。这种情况下,系统合成的复制构造函数往往只是给这个指针变量分配了内存,但是没有对指针所指向的对象(一个字符串,另外一个类)分配资源,使用系统合成的复制构造函数往往达不到程序员的意图。举两个需要自己定义合成复制函数的例子:
1、Matrix类,其中,实际矩阵在构造函数中动态分配,在析构函数中删除。
2、Payroll类,这个类中为每个对象提供唯一ID。
第一个涉及内存的动态分配,当用已有的对象生成一个新对象时,复制构造函数必须为这个新对象动态分配内存,而系统默认的合成复制构造函数并没有这个功能,所以需要定义自己的复制构造函数。
第二个需要为每个对象提供唯一ID,利用已知的对象使用复制构造函数生成新对象时,系统默认的合成复制构造函数会一并地复制这个ID,使得新对象的ID和原对象的ID是一样的,所以需要定义自己的复制构造函数,生成唯一的ID。
赋值操作符:
复制和赋值常一起使用,可以使用合成复制构造函数的类通常也可以使用合成赋值操作符。一般而言,如果类需要复制构造函数,它也会需要复制操作符。
析构函数:
构造函数可以分配一个缓冲区或打开一个文件,在构造函数中分配了资源之后,析构函数可以回收或者释放资源。
撤销类对象时会自动调用析构函数,动态分配的对象只有在指向该对象的指针被删除时才撤销。没有删除指向该对象的指针,则不会运行析构函数,对象一直存在,导致内存泄漏。
析构函数通常用于释放在构造函数或在对象生命周期内获取的资源。
三法则:
如果类需要析构函数,则它也需要赋值操作符和复制构造函数。这三个复制控制成员对类的行为进行控制。
由上述我们可以得出,对于一个空类,系统也会产生默认的上述四类函数。