4.2构造函数和析构函数 在OOP中,凡是实用程序创建的对象都需要作某种形式的初始化。为此,在C++的类 说明中,引进了构造函数( constructor function),供创建类的实例时调用,并自动完成对象 的初始化。析构函数( destructor function)则用于释放对象定义时通过构造函数向系统所申 请的存储空间以及有关的系统资源。它是在对象离开其有效范围时自动调用 [例4.la]使用构造函数改写例4.1。EX4-1aCPP 4.2.1构造函数的特性 构造函数具有以下特性: (1)、构造函数的名称与它所属的类名相同,且是无返回值类型(任何返回类型,包括 void,都是非法的) (2)、一个类可以有一个以上的构造函数,重载构造函数参数个数或类型不一样。如果 编程时在类中没有显式定义构造函数,慢编译器会为类自动生成一个缺省的构造函数(不带 任何参数)。 (3)、构造函数是在以类去定义所属实例时,由编译器自动调用的。在C+中,执行某 对象的说明时,调用了构造函数,创建了该对象。它不同于一般的变量说明语句 (4)、构造函数与一般成员函数性质相同,同样要受到访问限制。一个定义于非 public 区的构造函数,则说明该类为私有类 例4.2]私有类实例。EX42CPP (5)、控制成员变量内存分配,为定义对象向系统申请内存。 (6)、构造函数不能用常规的调用方法,不可取它们的地址,不能被继承。 4.2.2构造函数的设计和使用 首先讨论构造函数设计面临的问题是什么?解决问题的思路和原则是什么? (1)、类中私有成员一般不作初始值设置,需要在定义对象时正确初始化,以确保对象 的有效性 (2)、采取显式调用成员函数进行对象初始化容易遗漏,造成对象无意义。因此使用构 造函数进行对象初始化为最佳选择 (3)一个类的不同对象需要有不同的初始化,因此采取两种方式解决此问题:参数化 的构造函数和多构造函数。 下面分别进行具体的介绍。 1、带参数的构造函数 [例4.3]具有带参数的构造函数的类的说明及使用。EX43CPP 一般情况下,构造函数往往使用缺省值,因为构造函数定义了缺省值,在函数调用时, 若无特别指定参数,便可以缺省值作初始化。而且也可以防止遗漏初始赋值。 缺省参数的构造函数用法与一般函数用法相同 [例4.3a]将上例函数改为带缺省参数的构造函数如EX43aCPP 注意:编译器一般是严格按函数定义时的顺序来确定实参的位置。如果参数调用时的实 参个数不足,编译器将优先匹配前面的形参,而不管它们是否有缺省值(参见函数一节)
4.2 构造函数和析构函数 在 OOP 中,凡是实用程序创建的对象都需要作某种形式的初始化。为此,在 C++的类 说明中,引进了构造函数(constructor function),供创建类的实例时调用,并自动完成对象 的初始化。析构函数(destructor function)则用于释放对象定义时通过构造函数向系统所申 请的存储空间以及有关的系统资源。它是在对象离开其有效范围时自动调用。 [例 4.1a] 使用构造函数改写例 4.1。EX4-1a.CPP 4.2.1 构造函数的特性 构造函数具有以下特性: (1)、构造函数的名称与它所属的类名相同,且是无返回值类型(任何返回类型,包括 void,都是非法的)。 (2)、一个类可以有一个以上的构造函数,重载构造函数参数个数或类型不一样。如果 编程时在类中没有显式定义构造函数,慢编译器会为类自动生成一个缺省的构造函数(不带 任何参数)。 (3)、构造函数是在以类去定义所属实例时,由编译器自动调用的。在 C++中,执行某 对象的说明时,调用了构造函数,创建了该对象。它不同于一般的变量说明语句。 (4)、构造函数与一般成员函数性质相同,同样要受到访问限制。一个定义于非 public 区的构造函数,则说明该类为私有类。 [例 4.2] 私有类实例。EX4_2.CPP (5)、控制成员变量内存分配,为定义对象向系统申请内存。 (6)、构造函数不能用常规的调用方法,不可取它们的地址,不能被继承。 4.2.2 构造函数的设计和使用 首先讨论构造函数设计面临的问题是什么?解决问题的思路和原则是什么? (1)、类中私有成员一般不作初始值设置,需要在定义对象时正确初始化,以确保对象 的有效性。 (2)、采取显式调用成员函数进行对象初始化容易遗漏,造成对象无意义。因此使用构 造函数进行对象初始化为最佳选择。 (3)一个类的不同对象需要有不同的初始化,因此采取两种方式解决此问题:参数化 的构造函数和多构造函数。 下面分别进行具体的介绍。 1、带参数的构造函数 [例 4.3] 具有带参数的构造函数的类的说明及使用。EX4_3.CPP 一般情况下,构造函数往往使用缺省值,因为构造函数定义了缺省值,在函数调用时, 若无特别指定参数,便可以缺省值作初始化。而且也可以防止遗漏初始赋值。 缺省参数的构造函数用法与一般函数用法相同。 [例 4.3a] 将上例函数改为带缺省参数的构造函数如 EX4_3a.CPP 注意:编译器一般是严格按函数定义时的顺序来确定实参的位置。如果参数调用时的实 参个数不足,编译器将优先匹配前面的形参,而不管它们是否有缺省值(参见函数一节)
此外,当构造函数只有一个函数时,可采用以下形式来定义对象 class name obj name=value 2、多构造函数 对于一个类的不同对象,当其需要不同类型和不同个数的初始化参数时,可以在一个 类中具有几个构造函数,以适应不同的情况 例4.3b]多构造函数的示例EX4_3bCP 注意避免错误:所定义的多个构造函数之前,在参数个数或类型上必须有差异;在定义 实例对象,调用多构造函数时,若使用缺省参数,特别要防止二义性 2、复制构造函数( copy constructor) 复制构造函数是一种特殊的构造函数 (1)、具有一般构造函数的功能,创建新对象时系统自动调用它 (2)、具有将参数传输对象按位拷贝的特殊功能。例如,当函数返回对象时,当用一个 对象初始化另一个对象时,都调用该复制构造函数 (3)编译系统具有为类产生一个缺省拷贝构造函数的功能。例如 在manO中的语句 pointer obl(30, 40) pointer ob2(ob1) 这里定义ob2时调用系统缺省拷贝构造函数,实现了对象拷贝(属于按位拷贝),ob1 与ob2完全相等,但是两个实体对象 (4)、用户可以自定义拷贝构造函数,定义的格式如下 class name( const class name &obj).i 其中,obj是一个对象引用,可用于初始化其他对象。如果有其他参数则在此后列出 如果缺省,则这个引用对象不能省。 Const是理论上的限定词,也可以不是 const型。 例4.3c]加入拷贝构造函数实例EX4_3CCPP 注意:如果类中包含有指针成员,那么就要慎用缺省的拷贝构造函数。因为拷贝会使两 个对象的指针指向同一片内存区域,而非复制指针指向的内容。当释放时,有可能导致严重 的后果(见[例4.10])。 4.2.3析构函数的特性和用法 (1)、析构函数也是成员函数,与构造函数相对应,命名是在构造函数名前加~(波浪 线) (2)、析构函数只能是无返回值型 (3)、析构函数不能有任何参数 (4)、析构函数不能重载,一个只允许有一个析构函数。 当对象离开其有效范围,或被取消时,析构函数都将起作用。即释放对象所占用的内存 析构函数的定义,一般是由一系列的 delete组成 [例4.4]析构函数使用实例EX44CPP
此外,当构造函数只有一个函数时,可采用以下形式来定义对象: class_name obj_name=value; 2、多构造函数 对于一个类的不同对象,当其需要不同类型和不同个数的初始化参数时,可以在一个 类中具有几个构造函数,以适应不同的情况。 [例 4.3b] 多构造函数的示例 EX4_3b.CPP。 注意避免错误:所定义的多个构造函数之前,在参数个数或类型上必须有差异;在定义 实例对象,调用多构造函数时,若使用缺省参数,特别要防止二义性。 2、 复制构造函数(copy constructor) 复制构造函数是一种特殊的构造函数: (1)、具有一般构造函数的功能,创建新对象时系统自动调用它。 (2)、具有将参数传输对象按位拷贝的特殊功能。例如,当函数返回对象时,当用一个 对象初始化另一个对象时,都调用该复制构造函数。 (3)编译系统具有为类产生一个缺省拷贝构造函数的功能。例如: 在 main()中的语句 pointer ob1(30,40); pointer ob2(ob1); 这里定义 ob2 时调用系统缺省拷贝构造函数,实现了对象拷贝(属于按位拷贝),ob1 与 ob2 完全相等,但是两个实体对象。 (4)、用户可以自定义拷贝构造函数,定义的格式如下: class_name(const class_name &obj){…} 其中,obj 是一个对象引用,可用于初始化其他对象。如果有其他参数则在此后列出, 如果缺省,则这个引用对象不能省。Const 是理论上的限定词,也可以不是 const 型。 [例 4.3c] 加入拷贝构造函数实例 EX4_3C.CPP。 注意:如果类中包含有指针成员,那么就要慎用缺省的拷贝构造函数。因为拷贝会使两 个对象的指针指向同一片内存区域,而非复制指针指向的内容。当释放时,有可能导致严重 的后果(见[例 4.10])。 4.2.3 析构函数的特性和用法 (1)、析构函数也是成员函数,与构造函数相对应,命名是在构造函数名前加~(波浪 线)。 (2)、析构函数只能是无返回值型。 (3)、析构函数不能有任何参数。 (4)、析构函数不能重载, 一个只允许有一个析构函数。 当对象离开其有效范围,或被取消时,析构函数都将起作用。即释放对象所占用的内存。 析构函数的定义,一般是由一系列的 delete 组成。 [例 4.4] 析构函数使用实例 EX4_4.CPP