在这里我会介绍一些关于C++类的一些特性,其中包括类的四大默认函数,构造函数、拷贝构造函数、赋值构造函数和析构函数,以及调用构造函数与析构函数的顺序。
一、构造函数
1、构造函数是类中一种特殊的成员函数;
2、构造函数不需要用户调用,而在建立对象时自动执行;
3、构造的名字必须与类名相同,不能由用户任意命名;
4、构造函数的功能是由用户定义的,用户根据对象初始化的要求设计函数体和函数参数;
class Time{ // 时间类
public:
// 构造函数
Time(){
m_nHour = 0;
m_nMin = 0;
m_nSec = 0;
m_szRecord = NULL;
}
// 带参数的构造函数
Time(int _nHour, int _nMin, int _nSec, char* _szRecord){
m_nHour = _nHour;
m_nMin = _nMin;
m_nSec = _nSec;
int nLength = strlen(_szRecord);
if(nLength == 0)
break;
m_szRecord = new char[nLength];
if(NULL != m_szRecord)
strcpy(m_szRecord, _szRecord);
}
};
二、拷贝构造函数
1、拷贝构造函数必须在构造对象时使用,即定义对象时;
2、在系统默认的拷贝构造,对指针的赋值时为浅拷贝,可能会导致直接对位的赋值,从而导致出现野指针情况,学手动处理为深拷贝,具体如下方代码所示;
3、自定义拷贝构造函数是一种良好的风格,可阻止编译器形成默认拷贝构造函数,提高源码效率
class Time{ // 时间类
public:
// 拷贝构造函数
Time(const Time& _tDate){
m_nHour = _tDate.GetHour();
m_nMin = _tDate.GetMin();
m_nSec = _tDate.GetSec();
char* szRecord = GetRecord;
int nLength = strlen(szRecord);
if(nLength == 0)
break;
m_szRecord = new char[nLength];
if(NULL != m_szRecord)
strcpy(m_szRecord, szRecord);
}
};
三、析构函数
1、析构函数也是一类特殊的函数,当对象的生命期结束时,会自动执行析构函数;
2、析构函数的作用在于撤销对象占用内存之前完成一些清理和善后的工作;
3、析构函数的名字是类名前面加一个“~”符号;
4、一个类可以由多个构造函数,但只能有一个析构函数;
class Time{ // 时间类
public:
// 析构函数
~Time(){
if(m_szRecord != NULL)
delete[] m_szRecord;
}
};
四、赋值构造
1、C++支持自定义类型的对象之间的赋值操作,而赋值功能的实现主要依靠自定义类中的赋值函数,该赋值函数可以由编译器隐式地定义在自定义类中,也可以由用户通过重载赋值运算符=的重载显式地定义在自定义类中;
2、当类中存在数据成员存在指针时,自赋值操作可能带来灾难性的后果;
3、赋值函数只能是类的非静态成员函数;
4、赋值运算符重载不能被继承;
#include <iostream>
using namespace std;
class Time{ // 时间类
public:
// 构造函数
Time(){
m_nHour = 0;
m_nMin = 0;
m_nSec = 0;
m_szRecord = NULL;
}
// 带参数的构造函数
Time(int _nHour, int _nMin, int _nSec, char* _szRecord){
m_nHour = _nHour;
m_nMin = _nMin;
m_nSec = _nSec;
int nLength = strlen(_szRecord);
if(nLength == 0)
break;
m_szRecord = new char[nLength];
if(NULL != m_szRecord)
strcpy(m_szRecord, _szRecord);
}
// 拷贝构造函数
Time(const Time& _tDate){
m_nHour = _tDate.GetHour();
m_nMin = _tDate.GetMin();
m_nSec = _tDate.GetSec();
char* szRecord = GetRecord;
int nLength = strlen(szRecord);
if(nLength == 0)
break;
m_szRecord = new char[nLength];
if(NULL != m_szRecord)
strcpy(m_szRecord, szRecord);
}
// 析构函数
~Time(){
if(m_szRecord != NULL)
delete[] m_szRecord;
}
// 赋值函数
Time& operator=(const Time& _tDate){
m_nHour = _tDate.GetHour();
m_nMin = _tDate.GetMin();
m_nSec = _tDate.GetSec();
char* szRecord = GetRecord;
int nLength = strlen(szRecord);
if(nLength == 0)
break;
m_szRecord = new char[nLength];
if(NULL != m_szRecord)
strcpy(m_szRecord, szRecord);
return *this;
}
// 普通成员函数
void SetTime();
void ShowTime();
int GetHour() const;
int GetMin() const;
int GetSec() const;
char* GetRecord() const;
private:
int m_nHour; // 小时
int m_nMin; // 分钟
int m_nSec; // 秒
char* m_szRecord; // 备注
};
//定义普通成员函数
void Time::SetTime(){
cin>>m_nHour>>m_nMin>>m_nSec;
}
void Time::ShowTime(){
cout<<m_nHour<<":"<<m_nMin<<":"<<m_nSec;
}
int Time::GetHour() const
{
return m_nHour;
}
int Time::GetMin() const
{
return m_nMin;
}
int Time::GetSec() const
{
renturn m_nSec;
}
char* Time::GetRecord() const
{
return m_szRecord;
}
int main(){
Time tTest_1(11,12,12, “Date”);
tTest_1.ShowTime();
Time tTest_2;
tTest_2.SetTime();
tTest_2.ShowTime();
// 拷贝构造
Time tTest_3 = tTest_1;
// 赋值函数
tTest_3 = tTest_2;
return 0;
}
五、构造函数及析构函数的调用顺序
1、基类的构造函数按照定义顺序执行构造函数;
2、基类的析构函数按照定义的反顺序执行析构函数;
3、派生类构造函数的执行顺序:
(1)先执行基类构造函数,调用顺序按照它们被继承时的声明顺序(从左到右);
(2)在执行内嵌成员对象的构造函数,调用顺序按照它们在类中的声明顺序(从上到下);
(3)最后执行派生类的构造函数;
4、派生类析构函数的执行顺序:
(1)先执行派生类的析构函数;
(2)在执行内嵌成员对象的析构函数,调用顺序与构造函数相反;
(3)最后执行基类的析构函数,调用顺序与构造函数相反;