构造函数:
是在对象已经具有空间以后做一些初始化的工作,不负责分配空间
是成员函数的一种,与类名相同,可以带参,无返回值,对对象做初始化
类默认有构造函数,无参无操作
有对象生成时一定调用构造函数
一个类可有多个构造函数
class Rectangle:
{
private:
int w,h;
public:
Rectangle(int i, int j=0);
Rectangle();
Rectangle(Rectangle r1, Rectangle r2);
};
//三个构造函数
Rectangle::Rectangle(int i, int j=0){
w = i;
h = j;
}
Rectangle::Rectangle(){
w = 0;
h = 0;
}
Rectangle::Rectangle(Rectangle r1, Rectangle r2){
w = r1.w + r2.w;
h = r1.h + r2.h;
}
int main(){
//第二个,第一个,第三个构造函数
Rectangle r(),r1(1),r2(r,r1);
//Rectangle r; 也用第二个
}
构造函数在数组的使用
指针不会引发对象的生成:
Rectangle *r[3]; //不会调用任何构造函数,因为是一个指针数组
Rectangle *r[3]={new Rectangle(4), NULL, new Rectangle(1,2)} //只生成两个对象,new返回为指针
复制构造函数
形如 X::X( X& x) 或 X::X(const X& x) ,参数为同类对象的引用,无定义编译器默认生成,完成两个对象复制的功能
复制构造函数与无参构造函数区别:
1. 无参构造函数也称默认构造函数,不一定存在(你不写任何构造函数编译器才会默认生成)
2. 复制构造函数一定存在(要么你写要么编译器帮你写),复制构造函数只有一个
class Complex:{
private:
double img,re;
};
int main(){
Complex c1;
Complex c2(c1); //调用缺省的默认的复制构造函数,c2与c1一样
}
复制构造函数起作用的三种情况:
//1.
Complex c1;
//2.初始化同类的另一个对象
Complex c2(c1); //或Complex c2=c1;
//某函数Func()的参数是类A的对象,则Func调用时,类A的复制构造函数将被调用
class A:
{
public:
A(){};
A(A & a){cout<<"copy construct"<<endl};
};
void Func(A a1){}
int main(){
A a2;
Func(a2); //此时a1对象的初始化调用复制构造函数,但我们的复制构造函数不是拷贝,所以a1可
//能不是a2的拷贝
return 0;
}
//3.若函数Func的返回值为A的对象时,Func返回时A的复制构造函数被调用
class A:
{
public:
int v;
A(int n){v=n;};
A(const A & a){
v = a.v
cout<<"copy construct"<<endl
};
};
A Func(){
A a1(3);
return a1;
}
int main(){
cout<<Func().v<<endl; //3
return 0;
}
对象间的赋值不等于复制构造函数被调用比如:
Complex c1;
c1=c2;
为了减少函数调用时,复制构造函数调用所产生的时间开销,可以用常量引用参数
void Func(const A & a ){}
引用的参数与实参是一回事,不会生成对象,若想让函数内部操作改变形参不改变实参,加上const
类型转换构造函数
为了实现类型转换
只有一个参数且不是复制构造函数
需要时编译器自动调用,生成一个无名临时对象
class Complex:
{
public:
double a,b;
Complex(double i, double j){a=i;b=j;}
Complex(int i){a=i; b=0;} //double to int
};
int main(){
Complex c1(7,8); //7.0,8.0
Complex c2=12; //a=12,b=0
c1=9; //编译器将9自动转换为一个无名临时对象其a=9,b=0,再将这个临时对象赋给c1
return 0;
}
析构函数(destructor)
在对象消亡时被调用(可为释放空间等),一个类最多一个
若不写编译器会自动生成(什么都不做)
函数名为:‘~’ + ‘className’
无参无返回值
在对象的空间被回收前的操作
class String:
{
private:
char *p;
public:
String(){
p = new char[10];
}
~ String();
};
String::~ String(){
delete []p;
}
对象数组生命周期结束时,其中的每个元素的析构函数都会被调用
消亡的几种情况:
//1. main函数结束时
class A:
{
public:
int a;
~ A(){cout<< "destructor" <<endl;}
};
int main(){
A a[2];
cout<< "end main" <<endl;
return 0;
}
//输出结果为:
//end main
//destructor
//destructor
//2.new出的对象,delete时消亡,不delete不消亡
A *a;
a = new A;
delete a; //析构函数调用
A a1[3];
delete [] a; //析构函数调用三次
//3. 对象作为函数返回值,返回后调用析构函数
class A:
{
public:
int a;
~ A(){cout<< "destructor" <<endl;}
};
A func(A sa) //调用默认复制构造函数初始化形参sa
{
return sa; //返回形参sa后析构函数被调用
}
int main(){
A a;
a = func(a); //func(a)生成一个返回值对象(临时对象),用复制构造函数初始化,其值赋
//值给a,执行完这条语句后,临时对象消亡,调用析构函数
cout<< "end main" <<endl;
return 0; //main结束后,全局对象a消亡,调用析构函数
}
//输出结果为:
//destructor
//destructor
//end main
//destructor
相关实例
析构函数和构造函数被调用实例:
class A:
{
public:
int a;
A(int i){ //构造函数,也可算类型转换构造函数
a=i;
cout << "a" << a << " construct" << endl;
};
~ A(){
cout << "a"<< a << " destruct" << endl;
}
};
A a1(1); //step1:全局对象在main之前初始化,在整个程序结束后消亡
void func(){
static A a2(2); //step8:静态局部变量初始化,在全部程序结束后消亡
A a3(3); //step9:局部变量a3初始化,在func结束后消亡
cout << "func end" << endl;
}
int main(){
A a4(4); //step2:初始化a4,在main结束后消亡
a4 = 6; //step3:类型转换构造函数生成值为6的临时对象
//step4:临时对象赋值语句结束后消亡
cout << "main" << endl; //step5
{A a5(5);} //step6:局部对象a5生成
//step7:包含a5的最内层大括号结束后a5消亡
func();
cout << "end main" << endl;
}
//输出结果
// a1 construct
// a2 construct
// a4 construct
// a6 construct
// a6 destruct
// main
// a5 construct
// a5 destruct
// a2 construct
// a3 construct
// func end
// a3 destruct
// end main
// a6 destruct //先消亡main内的
// a2 destruct //因为a1比a2先初始化,后消亡
// a1 destruct
构造函数在不同编译器中表现
dev c++呼吁优化目的没有生成返回值临时对象,一般情况下没什么问题