对于类对象成员的初始化我们始终是建立成员函数然后手工调用该函数对成员进行赋值的,那么c++中对于类来有没有更方便的方式能够在对象创建的时候就自动初始化成员变量呢,这一点对操作保护成员是至关重要的,答案是肯定的。关于C++类成员的初始化,有专门的构造函数来进行自动操作而无需要手工调用,在正式讲解之前先看看c++对构造函数的一个基本定义:
1,C++规定,每个类必须有默认的构造函数,没有构造函数就不能创建对象。
2,若没有提供任何构造函数,那么C++自动提供一个默认的构造函数,该默认构造函数是一个没有参数的构造函数,它仅仅负责创建对象而不做任何赋值操作。
3,只要类中提供了任意一个构造函数,那么C++就不在自动提供默认构造函数。
4,类对象的定义和变量的定义类似,使用默认构造函数创建对象的时候,如果创建的是静态或者是全局对象,则对象的位模式全部为0,否则将会是随即的。
构造函数的作用是在创建对象时,系统自动调用它来给所创建的对象初始化。构造函数是在类体中进行说明的一种特殊的成员函数。
构造函数的特点:
1,构造函数是一种成员函数,它的说明在类体内,它的函数体可以写在类体内,也可以写在类体外。
2,构造函数是一种特殊的成员函数,该函数的名字与类名相同。定义和说明构造函数时,不必指明函数类型。
3,构造函数可以有一个参数或多个参数,也可以没有参数。(在说明的时候也可以设置默认值0
4,构造函数可以进行重载。
5,构造函数多用于创建对象时系统自动调用,也可以在程序中调用构造函数创建无名对象。
默认构造函数的特点:
1,默认构造函数时无参数的构造函数。定义格式为:<类名> :: <默认构造函数名> () { < 函数体> }
2,默认构造函数名与该类的类名相同。
3,默认构造函数可以由用户定义,其格式如上所示。当类中没有定义任何构造函数时,系统将自动生成一个函数体为空的默认构造函数。
4,在程序中定义一个没有给定初始值的对象时,系统将自动调用默认构造函数创建该对象。当该对象是外部的或静态的时,它的所有数据成员被初始化为0或空,当该对象是走动的时,它的所有数据成员的值是无意义的。
拷贝构造函数的特点:
同一个类中的两个对象时,可以用一个已知的对象去创建另一个对象。由一个对象初始化另一个对象时,系统将自动调用拷贝构造函数或默认拷贝构造函数。
拷贝构造函数的特点:
1,拷贝构造函数名字与类名相同,并且不必指明返回类型。
2,拷贝构造函数只有一个参数,并且该参数是该类的对象的引用。
3,拷贝构造函数的定义格式为:<类名> :: <拷贝构造函数名> ( <类名> & <引用名> ) { <函数体> }
4,如果一个类中没有定义拷贝构造函数,则系统自动生成一个默认拷贝构造函数。该默认拷贝构造函数的功能是将已知对象的所有数据成员的值拷贝给未知对象的所有对应的数据成员。
拷贝构造函数的用处:
1,用已知的对象创建同一个类的新对象。
2,在使用对象作为函数参数时,当实参值传递给形参时,系统将自动调用拷贝构造函数来实现这一传递。
3,当对象作为函数的返回值时,系统自动调用拷贝构造函数用返回值或对象值创建一个临时对象,然后再将这个临时对象赋值给调用函数中的某个接收函数返回值的对象。
析构函数
析构函数用来释放一个对象。当一个对象结束它的生存期时,系统将自动调用析构函数来释放该对象。析构函数的作用正好与构造函数的作用相反。析构函数是在类体中进行说明的一种特殊的成员函数。
析构函数的特点:
1,析构函数是一种成员函数,它的函数体可以写在类体内,也可以写在类体外。
2,析构函数名与类名相同,与构造函数名的区别在于析构函数名前加“~”,表明它的功能与构造函数功能相反。
3,析构函数没有参数,不能重载,也不必指定函数类型,一个类中只能有一个析构函数。
4,析构函数通常是被系统自动调用的,在下面的情况中析构函数将被自动调用;
(1),当一个对象的生存期结束时,例如,在一个函数体内定义的对象,当该函数结束时,自动调用析构函数释放对象。
(2),使用new运算符创建的对象,在使用delete运算符释放该对象时,系统将自动调用析构函数。
默认析构函数的特点:
如果一个类中没有定义析构函数时,系统将自动生成一个默认析构函数,格式为;
<类名> :: ~<默认析构函数名>() { }
默认析构函数与用户定义的析构函数具有相同的特点,其区别仅在于,默认析构函数是系统自动生成的,并且是一个空函数。
例一分析下面的程序题熟悉调用构造函数和析构函数;
<span style="font-size:18px;">#include <iostream.h>//文件包含命令
class Tdate//定义一个Tdate的类
{
public://四个公有成员函数
Tdate(int y,int m,int d);//定义的带三个参数的构造函数
Tdate() { cout<<"Default Constructor called\n";}//用户定义的默认构造函数
~Tdate();//用户定义的析构函数
void Print();//一个无返回值的成员函数
private://两个三个私有数据成员
int year,month,day;
};
Tdate::Tdate(int y,int m,int d)//类体外构造函数的函数体
{
year=y;
month=m;
day=d;
cout<<"Constructor called\n"<<d<<endl;
}
Tdate::~Tdate()//类体外析构函数的函数体
{
cout<<"Constructor called\n"<<day<<endl;
}
void Tdate::Print()//类体外成员函数的函数体
{
cout<<year<<","<<month<<","<<day<<endl;
}
void main()
{
static Tdate d1;//创建的一个静态的对象d1,这时调用默认构造函数,由于是静态的,数据成员的值均为0
Tdate d2(2000,4,2);//创建一个自动类的对象d2,这时调用构造函数
cout<<"d1 is ";
d1.Print();
cout<<"d2 is ";
d2.Print();
}</span>
分析:(1)由于d1是静态的无初始值的对象,因此调用默认构造函数,输出Default Constructor called
(2)由于d2是由初始值的对象,因此调用构造函数,输出Constructor called 2
(3)由于d1是静态的对象,因此各个数据成员的值均为0,输出d1 is 0,0,0
(4)由于d2是初始化的对象,因此输出d2 is 2000,4,2
(5)由于两个对象的生存期已结束,因此要调用析构函数来释放对象,释放对象遵循对象释放的顺序与创建的顺序相反,先创建的对象后释放,后创建的对象先释放,输出Constructor called 2和Constructor called 0
例二熟悉调用拷贝构造函数的过程;
<span style="font-size:18px;">#include <iostream.h>//文件包含命令
class Tpoint//创建一个Tpoint的类
{
public://五个公有成员函数
Tpoint(int x,int y)//带参数的构造函数
{ X=x; Y=y; }
Tpoint(Tpoint &p);//带参数的拷贝构造函数
~Tpoint()//用户定义的析构函数
{ cout<<"Constructor called\n"; }
int Xcoord()//类内带有函数体的成员函数
{ return X; }
int Ycoord()
{ return Y; }
private://两个私有的数据成员
int X,Y;
};
Tpoint::Tpoint(Tpoint &p)//带有参数的拷贝构造函数的函数体
{
X=p.X;
Y=p.Y;
cout<<"Copy-initialization Constructor called\n";
}
void main()
{
Tpoint p1(4,9);//创建一个带参数的对象
Tpoint p2(p1);//创建一个用已知的对象去初始化未知对象的对象
Tpoint p3=p2;
cout<<"p3=("<<p3.Xcoord()<<","<<p3.Ycoord()<<")\n";
}
</span>
分析: (1)由于创建的对象p1带有参数,因此先调用构造函数进行初始化
(2)由于创建的对象p2是引用对象p1,因此调用拷贝构造函数,输出Copy-initialization Constructor called
(3)由于创建的对象p3也是引用对象p2,又一次调用拷贝构造函数,输出 Copy-initialization Constructor called
(4)初始化完毕后,输出类对象p3的坐标,输出p3=(4,9)
(5)当三个对象均结束生存期后,调用新构函数释放对象。输出三次 Constructor called