构造函数和析构函数是在类体中说明的两种特殊的成员函数。构造函数是在创建对象时,使用给定的值来将对象初始化。析构函数的功能正好相反,是在系统释放对象前,对对象做一些善后工作。
1. 构造函数
构造函数可以带参数、可以重载,同时没有返回值。构造函数是类的成员函数,系统约定构造函数名必须与类名相同。构造函数提供了初始化对象的一种简单的方法。
对构造函数,说明以下几点:
1.构造函数的函数名必须与类名相同。构造函数的主要作用是完成初始化对象的数据成员以及其它的初始化工作。
2. 在定义构造函数时,不能指定函数返回值的类型,也不能指定为void类型。
3. 一个类可以定义若干个构造函数。当定义多个构造函数时,必须满足函数重载的原则。
4.构造函数可以指定参数的缺省值。
5.若定义的类要说明该类的对象时,构造函数必须是公有的成员函数。如果定义的类仅用于派生其它类时,则可将构造函数定义为保护的成员函数。
由于构造函数属于类的成员函数,它对私有数据成员、保护的数据成员和公有的数据成员均能进行初始化。
class A{
float x,y;
public:
A(float a, float b=10) { x=a; y=b; }
A() { x=0; y=0;}
void Print(void) { cout<<x<<'\t'<<y<<endl; }
};
void main(void)
{ A a1, a2(20.0), a3(3.0, 7.0);
a1.Print();
a2.Print();
a3.Print();
}
|
每一个对象必须要有相应的构造函数。若没有显式定义构造函数,系统默认缺省的构造函数。
class A{
float x,y;
public:
A() {}
void Print(void) { cout<<x<<'\t'<<y<<endl; }
};
|
对局部对象,静态对象,全局对象的初始化对于局部对象,每次定义对象时,都要调用构造函数。
对于静态对象,是在首次定义对象时,调用构造函数的,且由于对象一直存在,只调用一次构造函数。
对于全局对象,是在main函数执行之前调用构造函数的。
class A
{ int x,y;
public:
A(int a){ x=a; cout<<“1\n”;}
A(int a, int b) { x=a,y=b;cout<<“2\n”;}
};
A a1(3);
void f(void) { A b(2,3);}
void main(void)
{ A a2(4,5);
f(); f();
}
|
class A{
float x,y;
public:
A(float a, float b){x=a;y=b;cout<<"初始化自动局部对象\n";}
A(){ x=0; y=0; cout<<"初始化静态局部对象\n";}
A(float a){ x=a; y=0; cout<<"初始化全局对象\n"; }
void Print(void){ cout<<x<<'\t'<<y<<endl; }
};
A a0(100.0);//定义全局对象
void f(void)
{ cout<<" 进入f()函数\n";A a2(1,2);
static A a3; //初始化局部静态对象
}
void main(void)
{ cout<<"进入main函数\n";
A a1(3.0, 7.0);//定义局部自动对象
f(); f(); }
|
缺省的构造函数
在定义类时,若没有定义类的构造函数,则编译器自动产生一个缺省的构造函数,其格式为:
className::className() { }
缺省的构造函数并不对所产生对象的数据成员赋初值;即新产生对象的数据成员的值是不确定的。
class A{
float x,y;
public:
A(){ }//缺省的构造函数,编译器自动产生,可以不写
float Sum(void) { return x+y; }
void Set(float a,float b) { x=a; y=b;}
void Print(void) { cout<<"x="<<x<<'\t'<<"y="<<y<<endl; }
};
void main(void)
{ A a1,a2;//产生对象时,自动调用缺省的构造函数,不赋值
a1.Set (2.0,4.0);
cout<<"a1: ";
a1.Print ();
cout<<"a1.sum="<<a1.Sum ()<<endl;
a2.Print();//打印随机值
}
|
关于缺省的构造函数,说明以下几点:
1、在定义类时,只要显式定义了一个类的构造函数,则编译器就不产生缺省的构造函数
2、所有的对象在定义时,必须调用构造函数
不存在没有构造函数的对象!
class A{
float x,y;
public:
A(float a,float b) { x=a; y=b; }
void Print(void){ cout<<x<<'\t'<<y<<endl; }
};
void main(void)
{ A a1;
A a2(3.0,30.0);
}
|
3、在类中,若定义了没有参数的构造函数,或各参数均有缺省值的构造函数也称为缺省的构造函数,缺省的构造函数只能有一个。
4、产生对象时,系统必定要调用构造函数。所以任一对象的构造函数必须唯一。
class A{
float x,y;
public:
A(float a=10,float b=20){ x=a; y=b; }
A(){ }
void Print(void){ cout<<x<<'\t'<<y<<endl; }
};
void main(void)
{ A a1;
A a2(3.0,30.0);
}
|
构造函数与new运算符
可以使用new运算符来动态地建立对象。建立时要自动调用构造函数,以便完成初始化对象的数据成员。最后返回这个动态对象的起始地址。
用new运算符产生的动态对象,在不再使用这种对象时,必须用delete运算符来释放对象所占用的存储空间。
用new建立类的对象时,可以使用参数初始化动态空间。
class A{
float x,y;
public:
A(float a, float b) { x=a;y=b; }
A() { x=0; y=0; }
void Print(void) { cout<<x<<'\t'<<y<<endl; }
};
void main(void)
{ A *pa1,*pa2;
pa1=new A(3.0, 5.0);//用new动态开辟对象空间,初始化
pa2=new A;//用new动态开辟空间,调用构造函数初始化
pa1->Print();
pa2->Print();
delete pa1; //用delete释放空间
delete pa2; //用delete释放空间
}
|
2. 析构函数
析构函数的作用与构造函数正好相反,是在对象的生命期结束时,释放系统为对象所分配的空间,即要撤消一个对象。
析构函数也是类的成员函数,定义析构函数的格式为:
ClassName::~ClassName( )
{
......
// 函数体;
}
析构 函数的特点如下:
1、析构函数是成员函数,函数体可写在类体内,也可写在类体外。
2、析构函数是一个特殊的成员函数,函数名必须与类名相同,并在其前面加上字符“~”,以便和构造函数名相区别。
3、析构函数不能带有任何参数,不能有返回值,不指定函数类型。
4、一个类中,只能定义一个析构函数,析构函数不允许重载。
5、析构函数是在撤消对象时由系统自动调用的。
在程序的执行过程中,当遇到某一对象的生存期结束时,系统自动调用析构函数,然后再收回为对象分配的存储空间。
class A{
float x,y;
public:
A(float a,float b)
{ x=a;y=b;cout<<"调用非缺省的构造函数\n";}
A() { x=0; y=0; cout<<"调用缺省的构造函数\n" ;}
~A() { cout<<"调用析构函数\n";}
void Print(void) { cout<<x<<'\t'<<y<<endl; }
};
void main(void)
{ A a1;
A a2(3.0,30.0);
cout<<"退出主函数\n";
}
|
在程序的执行过程中,对象如果用new运算符开辟了空间,则在类中应该定义一个析构函数,并在析构函数中使用delete删除由new分配的内存空间。因为在撤消对象时,系统自动收回为对象所分配的存储空间,而不能自动收回由new分配的动态存储空间。
class Str{
char *Sp; int Length;
public:
Str(char *string)
{ if(string){ Length=strlen(string);
Sp=new char[Length+1];
strcpy(Sp,string);
}
else Sp=0;
}
void Show(void){ cout<<Sp<<endl; }
~Str() { if(Sp) delete []Sp; }
};
void main(void)
{ Str s1("Study C++");
s1.Show();
}
|
用new运算符为对象分配动态存储空间时,调用了构造函数,用delete删除这个空间时,调用了析构函数。当使用运算符delete删除一个由new动态产生的对象时,它首先调用该对象的析构函数,然后再释放这个对象占用的内存空间。
class A{
float x,y;
public:
A(float a, float b){ x=a; y=b; cout<<"调用了构造函数\n";}
void Print(void){ cout<<x<<'\t'<<y<<endl; }
~A() { cout<<"调用了析构函数\n"; }
};
void main(void)
{ cout<<"进入main()函数\n";
A *pa1;
pa1=new A(3.0, 5.0);//调用构造函数
pa1->Print();
delete pa1; //调用析构函数
cout<<"退出main()函数\n";
}
|