目录
- 前言
- 初始化和清理的概念
- 构造函数和析构函数的作用
- 构造函数的作用
- 析构函数的作用
- 使用构造函数和析构函数的注意事项
- 默认的构造函数和析构函数
- 结束语
前言
在使用c语言开发的项目场景中,我们往往会遇到申请空间的需求,同时也肯定遇到过程序运行一段时间后会卡死(崩溃)的情况,分析下来大概率可能是内存堆空间容量不够用所导致,我们作为开发人员在设计时,往往在写了malloc申请函数之后,会容易忘记释放该申请的内存堆空间。但是上述问题,往往在c++中可以得到很好解决。
初始化和清理的概念
- 当对象产生时,必须初始化成员变量,当对象销毁前,必须清理对象
- 初始化用构造函数,清理用析构函数,这两个函数是编译器调用
构造函数和析构函数的作用
构造函数的作用
先看代码:
class Maker
{
public:Maker(){a = 10;cout << "构造函数" << endl;}~Maker(){cout << "析构函数" << endl;}
public:int a;
};void test01()
{Maker m;int b = m.a;cout << b << endl;
}
好!按照老样子,接下来开始详细讲解每行代码的用处,以及为什么这样写!
void test01()
{Maker m;int b = m.a;cout << b << endl;
}
Maker m;
//首先实例化对象,并且该实例化对象为m。
int b = m.a;
cout << b << endl;
//将实例化对象m的成员变量a赋值给b,并且将b打印出来。
class Maker
{
public:Maker(){a = 10;cout << "构造函数" << endl;}~Maker(){cout << "析构函数" << endl;}
public:int a;
};
Maker(){a = 10;cout << "构造函数" << endl;}
//该函数即构造函数,构造函数的作用时初始化成员变量,并且是编译器自动调用的,即只要我们实例化对象之后,则编译器会自动调用构造函数进行初始化。
//构造函数的作用其实就类似与我们使用c语言开发时使用的malloc()函数
//在该构造函数中主要将10赋值给a。
~Maker()
{cout << "析构函数" << endl;
}
//该函数为析构函数,析构函数的作用其实就类似与我们使用c语言开发时使用的free()函数,所以在对象销毁前,编译器同样会自动调用析构函数。
接下来我们看下上述代码的执行结果如何?
由上图可知 ,确实会如同我们在前面讲述一样,系统编译器会自动调用构造函数和析构函数。
析构函数的作用
先看代码:
class Maker2
{
public:Maker2(const char *name,int age){cout << "有参构造" << endl;pName = (char*)malloc(strlen(name) + 1);strcpy(pName, name);mAge = age;}void printMaker2(){cout << "name:" << pName << " age:" << mAge << endl;}~Maker2(){cout << "析构函数" << endl;if (pName != NULL){free(pName);pName = NULL;}}
private:char *pName;int mAge;
};void test02()
{Maker2 m2("翠花",18);m2.printMaker2();
}
好!按照老样子,接下来开始详细讲解每行代码的用处,以及为什么这样写!
void test02()
{Maker2 m2("翠花",18);m2.printMaker2();
}
//首先实例化对象,并且该实例化对象为m2
。
//并且这里调用的是有参构造函数的方法,将"翠花"
和18
作为有参构造函数的形参传进去。
//调用类中的printMaker2
函数将pName
和mAge
打印出来。
Maker2(const char *name,int age)
{cout << "有参构造" << endl;pName = (char*)malloc(strlen(name) + 1);strcpy(pName, name);mAge = age;
}
//该函数为构造函数,并且使用的和上一个程序中构造形式不同,使用的是有参构造,其中有两个形参,分别是char类型的指针变量name和int类型的age。
pName = (char*)malloc(strlen(name) + 1);
//使用malloc函数在堆区中申请一段空间用来存放通过形参传入的name值。
strcpy(pName, name);
//将name指向的那段内存空间的内容复制到pName指向的那段内存空间中,即pName指向的那段内存空间中存放了真正传入该函数的name值。
mAge = age;
//简单的赋值操作。
~Maker2()
{cout << "析构函数" << endl;if (pName != NULL){free(pName);pName = NULL;}
}
//该函数为析构函数,在该函数中首先判断在构造函数申请的堆区空间有没有申请成功,如果申请成功,则会调用free函数去释放掉该空间,并且将其指针指向NULL。
接下来我们看下上述代码的执行结果如何?
由上图可知 ,确实会如同我们在前面讲述一样,系统编译器会自动调用构造函数和析构函数。同时成功传入参数。
使用构造函数和析构函数的注意事项
- 构造函数和析构函数的权限必须是公有的
- 构造函数可以重载
- 构造函数没有返回值,不能用void,构造函数可以有参数,析构函数没有返回值,不能用void,没有参数
- 有对象产生必然会调用构造函数,有对象销毁必然会调用析构函数。有多少个对象产生就会调用多少次构造函数,有多少个对象销毁就会调用多少次析构函数
默认的构造函数和析构函数
先看代码:
class Maker
{
public:Maker()//默认的构造函数,函数体是空的{}~Maker()//默认的析构函数,函数体也是空{}//编译器默认提供默认的构造函数和析构函数void printfMaker(){a = 100;cout << "a=" << a << endl;}
private:int a;
};
//即使我们在类中没有声明构造函数或者析构函数,也没关系,编译器中已经设置了默认的构造函数和析构函数,只不过在这两个函数体中都是空的,不做任何处理。
结束语
如果觉得这篇文章还不错的话,记得点赞 ,支持下!!!