C++构造函数与析构函数
作者:互联网
构造函数与析构函数
前言
C++中的构造函数和析构函数,分别用于实例化对象的初始化工作以及对象资源的回收工作。
0x00 为什么要有构造函数和析构函数?
在一个类中,通常会有该类成员变量的接口以供外部访问。实例化一个类对象以后,要使用接口函数(Set函数)来设置类对象的值。
class Date
{
private:
int nYear;
int nMonth;
int nDay;
char* szFormat; // 格式化的日期字符串
public:
void SetYear(int nYear);
void SetMonth(int nMonth);
void SetDay(int nDay);
void SetDate(int nYear, int nMonth, int nDay);
// get接口省略...
char* GetDate(); // 得到格式化的日期
};
int main(int argc, char* argv[])
{
Date date;
date.SetDate(2022, 2, 27); // 使用接口函数来设置对象的值
return 0;
}
这里有一个问题,就是实例化对象时,对象没有初始值。用接口来设置初值会感觉很不自然。并且格式化日期指针没有值。
如果按照C语言的想法,会提供一个Init函数用来实现对象的初始化。那么在实例化对象时,必须先调用Init方法用于初始化该对象。Init方法必须在实例化以后立即调用。
void Init(int nYear, int nMonth, int nDay)
{
this->nYear = nYear;
this->nMonth = nMonth;
this->nDay = nDay;
szFormat = (char*)maloloc(strlen("1970-01-01") + 1);
}
char* GetDate()
{
// format过程省略
return szFormat;
}
该对象还有个保存堆空间的指针变量,为此还需要为该对象提供一个释放对象资源方法Destroy函数。
void Destroy()
{
if (szFormat != nullptr)
{
free(szFormat);
szFormat = nullptr;
}
}
因此,正常使用该类的步骤应该是:
Date date;
date.Init(2022, 2, 27);
// do something ...
data.Destroy();
现在的问题是,如果使用者忘了调用或者没有调用Init函数和Destroy函数则可能会有内存泄漏。放在其他项目中可能会有意想不到的结果。
为此C++提供了构造函数和析构函数,分别用于实例化对象的初始化以及对象资源的回收。能够完美解决上面的问题。
0x01 构造函数
在实例化对象时会自动调用构造函数。
1.与类名同名,无返回值。
2.允许重载。
3.不允许显式调用。因为如果构造函数中有申请内存,显式调用会重复申请内存,原来申请的内存地址将会被覆盖。例如上面的Init函数的重复调用。但vs中,可以使用[对象.类名::构造函数]来显式调用。
class VectorInt2D //类
{
public:
VectorInt2D()
{
Init();
}
VectorInt2D(int x) // 构造函数可以重载
{
Init(x);
}
VectorInt2D(int x, int y) // 构造函数可以重载
{
Init(x, y);
}
void Init(int x = 0, int y = 0)
{
uint32_t nLen = strlen("VectorInt2D") + 1;
m_pszClassName = new char[nLen];
strcpy_s(m_pszClassName, nLen, "VectorInt2D");
this->x = x;
this->y = y;
}
~VectorInt2D()
{
if (m_pszClassName != nullptr)
{
delete m_pszClassName;
m_pszClassName = nullptr;
}
}
char* GetClassName()
{
return m_pszClassName;
}
private:
char* m_pszClassName;
int x;
int y;
};
int main(int argc, char* argv[])
{
VectorInt2D pos1(2, 1); //实例化对象自动调用构造
pos1.VectorInt2D::VectorInt2D(); // 非标准
//pos1.VectorInt2D(); //error 不允许显式调用
return 0;
}
0x02 析构函数
在对象出作用域时调用。
1.函数名为类名前~,无返回值。
2.不允许带参数,不允许重载。
3.可以显示调用。向上面Destroy函数的调用,可以通过写代码来控制资源的合理释放,因此可以显式调用。
int main(int argc, char* argv[])
{
VectorInt2D pos1(2, 1);
pos1.~VectorInt2D(); // 显示调用析构函数
return 0;
}
0x03 构造函数与析构函数的失败问题
可以在构造函数中调用析构函数,因此构造函数中如果申请内存失败,可以直接调用析构函数。但是构造函数没有返回值,如何让外部知道构造函数是否成功?
标签:调用,函数,int,与析构,C++,Init,VectorInt2D,构造函数 来源: https://blog.csdn.net/ArthurHai521/article/details/123160794