构造函数
概念:成员变量为私有的,需要用一个公有函数来对他们进行初始化。同时这个函数有且仅在定义对象时自动执行一次。
特点:
- 函数名和类名相同
- 无返回值
- 对象构造(对象实例化)时系统自动调用对应的构造函数。
- 构造函数可以重载
- 构造函数可以在类中定义,也可以在类外,在类外定义需要指定类域。
- 如果类中没有给出构造函数,C++编译器会自动生成一个缺省的构造函数。但是只要我们自己定义了缺省的构造函数,编译器就不会再生成。
- 无参的构造函数和全缺省的构造函数都认为是缺省构造函数,缺省的构造函数只能有一个。
class date{
public:
//无参的构造函数
date();
//带参构造函数
date(int year, int month, int day){
_year = year;
_month = month;
_day = day;
}
//缺省参数的构造函数
date(int year = 2000, int month = 1, int day = 1){
_year = year;
_month = month;
_day = day;
}
//半缺省参数的构造函数
date(int year, int month = 1, int day = 1){
_year = year;
_month = month;
_day = day;
}
void DisPlay(){
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main(){
date d1;
d1.DisPlay();
date d2(2018, 7, 3);
d2.DisPlay();
// date d3();错误写法,但编译器不会报错
system("pause");
return 0;
}
拷贝构造函数
概念:创建对象时使用同类对象来进行初始化,拷贝构造函数是特殊的构造函数。
特点:
- 拷贝构造函数其实就是一个构造函数的重载。
- 拷贝构造函数必须使用引用传参,使用传值会引发无限递归。
- 若未定义,系统会默认缺省的拷贝构造函数,缺省的拷贝构造函数会依次拷贝类成员进行初始化。
class date{
public:
date(const date& d){
_year = d._year;
_month = d._month;
_day = d._day;
}
void DisPlay(){
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main(){
date d1;
date d2(d1);
date d3 = d2;
system("pause");
return 0;
}
析构函数
概念:当一个对象的生命周期结束,C++编译系统会自动调用一个成员函数,这个特殊的成员函数即析构函数。
特征:
- 析构函数在类名前加~
- 析构函数无参数无返回值
- 一个类有且仅有一个析构函数,若未定义,系统会自动生成缺省的析构函数
- 对象生命周期结束,系统会自动调用析构函数
- 析构函数体内并不是删除对象,而是做一些清理工作。这个清理工作可以理解为有一些成员需要动态释放。
- 先调用的析构函数后清理。
class Array{
public:
Array(int size){
_ptr = (int*)malloc(size*sizeof(int));
}
~Array(){
if (_ptr){
free(_ptr);
_ptr = 0;
}
}
private:
int* _ptr;
};
int main(){
Array arr(2);
system("pause");
return 0;
}
问题:系统会自动生成缺省的析构函数,为什么我们还要自己写析构函数?
上面的调用代码如果改成这样
int main(){
Array arr1(2);
Array arr2(arr1);
system("pause");
return 0;
}
arr1和arr2都指向同一地址空间,使用系统默认生成的析构函数,arr2析构后,arr1在析构就会出现问题。因为我们一般情况下我们需要自己来写析构函数。