一,引言
由于c语言常常会忘记初始化与销毁,造成许多麻烦。所以c++就引入了构造函数与析构函数,分别用来完成初始化与清理工作,且由编译器自动调用,这就避免了许多麻烦。
二,构造函数
构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,主要完成初始化工作保证每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次
构造函数特点如下:
1,函数名与类名相同。
2,无返回值。
3,对象实例化时编译器自动调用对应的构造函数。
4,构造函数可以重载
class Date
{
public:
// 1.无参构造函数
Date()
{}
// 2.带参构造函数
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1; // 调用无参构造函数
Date d2(2015, 1, 1); // 调用带参的构造函数
Date d3(); #不能这么写,会报错!!!
}
注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明,该函数无参,返回一个日期类型的的对象
5,无参的构造函数和全缺省的构造函数都称为默认构造函数,且防止冲突默认构造函数只能有一个
class Date
{
public:
#无参
Date()
{
_year = 1900;
_month = 1;
_day = 1;
}
#全缺省
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
6,如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成
class Date
{
public:
/*
// 如果用户显式定义了构造函数,编译器将不再生成
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
*/
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
return 0;
}
将Date类中构造函数屏蔽后,代码可以通过编译,因为编译器生成了一个无参的默认构造函数。将Date类中构造函数放开,代码编译失败,因为一旦显式定义任何构造函数,编译器将不再生成无参构造函数,Date类中的构造函数不是无参构造函数和全缺省构造函数,即不属于默认构造函数。若d1不进行传参,放开后报错,因为没有合适的默认构造函数可用。
对默认构造函数正确的态度应该是:面向需求编译器默认生成就可以满足,就不用自己写,不满足就需要自己写
7,C++把类型分成内置类型和自定义类型。内置类型就是语言提供的数据类型,如:int /char...,自定义类型就是我们使用class /struct /union等自己定义的类型。
不实现构造函数的情况下,编译器默认生成的构造函数只对自定义类型进行初始化,而内置类型不进行处理,只会给予随机值。
这是当初设计时留下的bug,无法进行修改。只能针对内置类型成员不初始化的缺陷,打补丁,即:内置类型成员变量在类中声明时可以给默认值。
class Date
{
private:
// 内置类型
int _year = 1; //这里不是初始化,而是缺省值
int _month = 1;
int _day = 1;
// 自定义类型
Time _t;
};
给了缺省值后,内置类型就可以初始化了
关于编译器生成的默认构造函数
- 例:time类显式定义默认构造函数,Date类不显式定义默认构造函数,date类中包含一个time类对象。
- 自定义类型成员初始化过程:初始化time对象的时候不是编译器直接去调用time类中定义的构造函数,而是先给date类生成默认构造函数,然后在date类的默认构造函数中再去调用time类中我们自己显式定义的默认构造函数。这个过程自定义类型成员必须要有显式默认构造函数,否则编译器不会给date类生成默认构造函数。
- 所以编译器生成的默认构造函数就是:生成一个函数去调用自定义类型成员的显式默认构造函数
三,析构函数
- 析构函数名是在类名前加上字符 ~。
- 无参数无返回值类型。
- 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载
- 对象生命周期结束时,C++编译系统系统自动调用析构
- 多个对象调用析构函数的顺序和创建顺序相反,哪个对象先压栈哪个对象先销毁。
class Time
{
public:
#析构函数
~Time()
{
cout << "~Time()" << endl;
}
private:
int _hour;
int _minute;
int _second;
};
class Date
{
private:
// 内置类型
int _year = 1970;
int _month = 1;
int _day = 1;
// 自定义类型
Time _t;
};
int main()
{
Date d;
return 0;
}
默认析构函数清理规则
- 同构默认生成构造函数类似 ,默认生成的析构函数同样对内置类型的成员变量不做处理,只在对象销毁时对自定义类型的成员会调用它们的析构函数来清理该自定义函数的成员变量。