3 构造函数和析构函数
3.1构造函数
在建立一个对象时,常常需要作某些初始化的工作(例如对数据赋予初值),C++提供了一种特殊的成员函数--构造函数(constructor)。这种函数与其他成员不同,不需要用户发“消息”来激活它,而是在建立对象时自动执行。构造函数是由用户定义的,它必须与类名同名,以便系统能识别它并把它作为构造函数。现在我们在前面声明的类中加入构造函数。
class stud
{private: //声明以下部分为私有的
int num;
char name[10];
char sex;
Public:
stud( ) //定义构造函数,函数名与类名相同
(num=10010;
strcpy(name," Wang-li" );
sex='F';} //以上3行为给数据赋初值
void display( ) //定义成员函数
{cout<<"num:"<<num<<endl;
cout<<"name:"<<name<<endl;
cout<<"sex:"<<sex<<endl; }
};
stud stud1: //在定义对象 stud1时自动执行构造函数
注意:构造函数不需用户调用,而是在定义一个对象时由系统自动执行,而且只能执行一次。构造函数一般声明为public,无返回值,也不需加void类型声明。现在写成一个完整的程序。
例15.1 建立一个对象,输出学生的学号、姓名、性别。
# include<string. h>
#include<iostream.h>
void main( )
{ class stud //声明一个类
{private: //私有部分
int num;
char name[10];
char sex ;
Public: //公用部分
stud( ) //定义构造函数,函数名与类名相同
{num=10010; //给数据赋初值
strcpy (name," Wang-li" );
sex='F';}
void display () //定义成员函数,输出对象的数据
{cout<<"num:"<<num<<endl;
cout<<"name:"<<name<<endl;
cout<<"sex:"<<sex<<endl;}
}
stud stud1; //在定义对象stud1时自动执行构造函数
stud1.display( ); //从对象外面调用display函数
}
可以看到整个程序很简单,它包括三部分:①声明一个类;②定义一个对象;③向对象发出消息,执行对象中的成员函数display。在定义stud1对象时自动执行了构造函数 ud(),因此对象中的数据成员均被赋了值。执行display函数输出以下信息:
num:10010
nome: Wang-li
sex: F
在程序中可以看到只有对象中的函数才能引用本对象中的数据。如果在对象外面直接用
cout<<stud1.num ;
企图输出学生的学号是不行的。由此可体会到类的特点。
如果要建立两个对象,分别对数据赋予初值,就不能这样定义构造函数stud了,因为它会使两个学生的初值相同,例如姓名都是Wang-li。应该分别赋予不同的初值。可将构造函数修改如下:
stud(int n,char nam[],chars ) //定义构造函数,有形参
{num=n;
strcpy(name,nam);
sex=s;
}
此时数据的值不由构造函数stud确定,而是在调用此函数时由实参传来。但应注意构造函数不同于一般的成员函数,不能这样调用:
stud1.stud(10010," Wang-li",'f'); //企图用调用一般成员函数的方法来调用构造函数
前已说明构造函数是在建立对象时调用的,因此实参应该在建立对象时给出。如:
stud stud1(10010,"Wang-li",’f’),stud2(10011,"Zhang-fun",'m');
现在定义了两个对象stud1和stud2,它们的数据初值是不同的。如果想分别输出两个学生的数据,可以用以下的语句:
stud1.display();
stud2.display();
此时的输出如下:
num:10010
name:Wang-li
sex:f
num:10011
name:Zhang-fun
sex:m
用户也可以不定义构造函数,编译系统会自动生成一个构造函数;该函数没有参数,不进行任何操作。
构造函数也可以重载,下面是两个重载函数:
stud( ) //在构造函数中对数据赋初值
{num=10010;
strcpy (name,"Wang-li");
sex='F';
}
stud(int n ,char nam[],char s) //有形参,由实参将值传给形参
{num=n;
strcpy (name,nam);
sex=s;
}
在定义对象时允许有实参和无实参。如:
stud studl; //不带实参,数据初值在构造函数中指定
stud stud2(10011,"Zhang-fun",'m' ); //带实参,数据初值由实参给出
3.2析构函数
析构函数(destructor)与构造函数相反,当对象脱离其作用域时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做“清理善后”的工作(例如在建立对象时用new开辟了一片内存空间,应在退出前在析构函数中用delete释放)。
析构函数名也应与类名相同,只是在函数名前面加一个波浪符~,例如~stud(),以区别于构造函数。它不能带任何参数,也没有返回值(包括void类型)。只能有一个析构函数,不能重载。如果用户没有编写析构函数,编译系统会自动生成一个缺省的析构函数,它也不进行任何操作。所以许多简单的类中没有用显式的析构函数。
例15.2 包含构造函数和析构函数的C++程序。
# include<string. h>
# include<iostream.h>
class stud //声明一个类
{private: // 私有部分
int num ;
char name[10];
char sex;
public: //公用部分
stud(int n ,char nam[],chars) //构造函数
{num=n;
strcpy(name,nam);
sex=s;}
~stud() //析构函数
{ }
void display ( ) //成员函数,输出对象的数据
{cout<<" num: "<<num<<endl;
cout<<"name: "<<name<<endl;
cout<<"sex: "<<sex<<endl ;}
void main ( )
{
stud stud1(10010,"Wang-li",'f'),stud2(10011,"Zhang-fun",'m'); //建立两个对象
stud1.display( ); //输出学生1的数据
stud2.display( ); //输出学生2的数据
}
现在把类的声明放在main函数之前,它的作用域是全局的。这样做可以使main函数更简练一些。在 main函数中定义了两个对象并且给出了初值。然后输出两个学生的数据。运行结果和例15.1中给出的相同。在本例中,析构函数并无任何实质上的作用,我们把它写出来,只是为了说明析构函数的使用方法。
在本程序中,成员函数是在类中定义的,如果成员函数的数目很多以及函数的长度很长,类的声明就会占很大的篇幅,不利于阅读程序。可以在类的外面定义成员函数,而在类中只用函数的原型作声明。
例15.3在类的外面定义成员函数。
#include<string. h>
#include<iostream.h> //声明一个类
class stud
{private:
int num ;
char name[10];
char sex ;
public:
stud(int n,char nam[],chars); //对构造函数的原型声明
~stud(); //对析构函数的原型声明
void display( ) ; //对成员函数 display的原型声明
};
stud: : stud (intn,char nam[].chars) //对构造函数的定义
{num=n;
strcpy(name,nam);
sex=s;} //对析构函数的定义
stud::~stud( )
{ } //对成员函数 display的定义
void stud:: display()
{cout<<"num:"<<num<<endl;
cout<<"name:"<<name<<endl;
cour<<"sex:"<<sex<<endl ;
}
void main( )
{
stud stud1(10010,"Wang-li”,'f'’),stud2(10011,"Zhang-fun",'m');
stud1,display( ): //输出学生1的数据
stud2.display(); //输出学生2的数据
}
请读者注意在类声明的外部定义函数,必须指定类名。函数首行的形式为
函数类型 类名::函数名(形参表列)
不能写成
void display( ) //未指定类名
如果这样写,编译系统会把它作为普通的函数处理,而不作为类中的成员函数。也不要写成:
stud::void display() //函数类型位置不对
stud::display()是一个整体,说明是stud 类中的 display 函数。不能把stud::和 display()分隔开来。
虽然函数在类的外部定义,但在调用成员函数时会根据类中函数的原型声明找到函数的定义(函数代码),从而执行该函数。
也可以将在类外部定义的函数声明为“内置函数”,这样在编译时就将函数代码代人到类中的函数调用处,以提高程序执行效率。只需在函数定义的首行最左端加上inline即可。如:
inline void stud:: display( )