3.4 构造函数与析构函数 构造函数
构造函数是一种特殊的成员函数,它主要用于为对象分配空间,进行初始化。构造函数的名字必须与类名相同,而不能由用户任意命名。它可以有任意类型的参数,但不能具有返回值。它不需要用户来调用,而是在建立对象时自动执行。
在建立对象的同时,采用构造函数给数据成员赋值,通常由以下两种形式
说明:
构造函数的名字必须与类名相同,否则编译程序将把它当做一般的成员函数来处理
构造函数没有返回值,在定义构造函数时,是不能说明它的类型的。
与普通的成员函数一样,构造函数的函数体可以写在类体内,也可写在类体外。
构造函数一般声明为共有成员,但它不需要也不能像其他成员函数那样被显式地调用,它是在定义对象的同时被自动调用,而且只执行一次。
构造函数可以不带参数。
成员初始化列表
在声明类时,对数据成员的初始化工作一般在构造函数中用赋值语句进行。此外还可以用成员初始化列表实现对数据成员的初始化。
**说明:**类成员是按照它们在类里被声明的顺序进行初始化的,与它们在成员初始化列表中列出的顺序无关。
带默认参数的构造函数
析构函数
析构函数也是一种特殊的成员函数。它执行与构造函数相反的操作,通常用于撤销对象时的一些清理任务,如释放分配给对象的内存空间等。析构函数有以下一些特点:
析构函数与构造函数名字相同,但它前面必须加一个波浪号(~)。
析构函数没有参数和返回值,也不能被重载,因此只有一个。
当撤销对象时,编译系统会自动调用析构函数。
**说明:**在以下情况中,当对象的生命周期结束时,析构函数会被自动调用:
如果定义了一个全局对象,则在程序流程离开其作用域时,调用该全局对象的析构函数。
如果一个对象定义在一个函数体内,则当这个函数被调用结束时,该对象应该被释放,析构函数被自动调用。
若一个对象是使用new运算符创建的,在使用delete运算符释放它时,delete会自动调用析构函数。
默认的构造函数和析构函数
如果没有给类定义构造函数,则编译系统自动生成一个默认的构造函数。
说明:
对没有定义构造函数的类,其公有数据成员可以用初始值列表进行初始化。
只要一个类定义了一个构造函数(不一定是无参构造函数),系统将不再给它提供默认的构造函数。
每个类必须有一个析构函数。若没有显示地为一个类定义析构函数,编译系统会自动生成一个默认的析构函数。
构造函数的重载
**注意:**在一个类中,当无参数的构造函数和带默认参数的构造函数重载时,有可能产生二义性。
拷贝构造函数
拷贝构造函数是一种特殊的构造函数,其形参是本类对象的引用。拷贝构造函数的作用是在建立一个新对象时,使用一个已存在的对象去初始化这个新对象。
拷贝构造函数具有以下特点:
因为拷贝构造函数也是一种构造函数,所以其函数名与类名相同,并且该函数也没有返回值。 拷贝构造函数只有一个参数,并且是同类对象的引用。 每个类都必须有一个拷贝构造函数。可以自己定义拷贝构造函数,用于按照需要初始化新对象;如果没有定义类的拷贝构造函数,系统就会自动生成一个默认拷贝构造函数,用于复制出与数据成员值完全相同的新对象。 自定义拷贝构造函数
调用拷贝构造函数的三种情况:
当用类的一个对象去初始化该类的另一个对象时; 当函数的形参是类的对象,调用函数进行形参和实参结合时; 当函数的返回值是对象,函数执行完成返回调用者时。 浅拷贝和深拷贝
浅拷贝,就是由默认的拷贝构造函数所实现的数据成员逐一赋值。通常默认的拷贝构造函数是能够胜任此工作的,但若类中含有指针类型的数据,则这种按数据成员逐一赋值的方***产生错误。
上述错误是因为stu1和stu2所指的内存空间相同,在析构函数释放stu1所指的内存后,再释放stu2所指的内存会发生错误,因为此内存空间已被释放。解决方法就是重定义拷贝构造函数,为其变量重新生成内存空间。