文章目录
- 前言
- 1.构造函数
- 1.1构造函数的使用
- 1.2构造函数的初始化列表
- 2.析构函数
前言
在C++中,类中存在 默认成员函数 ,那什么是 默认成员函数 ?
默认成员函数就是用户没有显示实现,编辑器会自动生成的成员函数。
一个类,在不写的情况下,会默认生成下面6个 默认成员函数 。其次,C++11以后还会增加两个 默认成员函数 , 移动构造 和 移动赋值 。这两个本篇文章不讲解。
默认成员函数 是公认的C++较难学习的部分。因此,我们在学习 默认成员函数 时,应从两个方面来学习:
- 我们不写时,默认生成的函数是否够用?
- 若是不够用,我们应该如何实现一个够用的成员函数?
1.构造函数
构造函数是特殊的成员函数。虽然名称里面带了构造,但是构造函数的主要任务不是开空间创建对象,而是对象实例化时初始化对象。构造函数的本质就是要替代我们以前Stack和Date类中的Init函数的功能。
构造函数的优点:
-
函数名与类名相同。
-
无返回值。 (返回值啥都不需要给,也不需要写void,不要纠结,C++规定如此)
-
对象实例化时系统会自动调用对应的构造函数。
-
构造函数可以重载。
-
如果类中没有显式定义构造函数,则C++编译器会自动生成⼀个无参的默认构造函数,⼀旦用户显
式定义编译器将不再生成。 -
无参构造函数、全缺省构造函数、我们不写构造时编译器默认生成的构造函数,都叫做默认构造函
数。无参构造函数和全缺省构造函数虽然构成函数重载,但是调用时会存在歧义。要注意很多同学会
认为默认构造函数是编译器默认生成那个叫默认构造,实际上无参构造函数、全缺省构造函数也是默
认构造,总结⼀下就是不传实参就可以调用的构造就叫默认构造。
注意:这三个函数不能同时存在,只能存在一个。 -
我们不写,编译器默认生成的构造,对内置类型成员变量的初始化没有要求,也就是说是是否初始
化是不确定的,看编译器。对于自定义类型成员变量,要求调用这个成员变量的默认构造函数初始
化。如果这个成员变量,没有默认构造函数,那么就会报错,我们要初始化这个成员变量,需要用
初始化列表才能解决。
1.1构造函数的使用
#include<iostream>
using namespace std;
typedef int STDateType;
class Stack {
public:
Stack(int n = 4)
{
_a = (STDateType*)malloc(sizeof(STDateType) * n);
if (nullptr == _a)
{
perror("malloc申请空间失败");
return;
}
_capacity = n;
_top = 0;
}
private:
STDateType* _a;
size_t _capacity;
size_t _top;
};
//两个Stack实现队列
class MyQueue {
public:
private:
Stack pushst;
Stack popst;
};
int main()
{
MyQueue mq;
return 0;
}
1.2构造函数的初始化列表
typedef int stdatetype;
class stack {
public:
stack(int n = 4)//初始化列表
:_capacity(n)
,_top(0)
{
_a = (stdatetype*)malloc(sizeof(stdatetype) * n);
if (nullptr == _a)
{
perror("malloc申请空间失败");
return;
}
}
private:
stdatetype* _a;
size_t _capacity;
size_t _top;
};
2.析构函数
析构函数与构造函数功能相反,析构函数不是完成对对象本身的销毁。比如局部对象存在局部栈帧,函数结束栈帧销毁,函数占用的资源得到释放。C++规定:对象结束时调用析构函数,完成对象中的资源清理释放工作。
析构函数的特点:
-
析构函数名是在类名前加上字符 ~。
-
无参数无返回值。 (这里跟构造类似,也不需要加void)
-
一个类只能有⼀个析构函数。若未显式定义,系统会自动生成默认的析构函数。
-
对象生命周期结束时,系统会自动调用析构函数。
-
跟构造函数类似,我们不写编译器自动生成的析构函数对内置类型成员不做处理,自定类型成员会
调用他的析构函数。 -
还需要注意的是我们显示写析构函数,对于自定义类型成员也会调用他的析构,也就是说自定义类
型成员无论什么情况都会自动调用析构函数。 -
如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,如Date;如
果默认生成的析构就可以用,也就不需要显示写析构,如MyQueue;但是有资源申请时,⼀定要
自己写析构,否则会造成资源泄漏,如Stack。
Stack:
class Stack {
public:
Stack(int n = 4)
{
_a = (STDateType*)malloc(sizeof(STDateType) * n);
if (nullptr == _a)
{
perror("malloc申请空间失败");
return;
}
_capacity = n;
_top = 0;
}
~Stack()
{
cout << "~Stack()" << endl;//析构函数被调用时,打印“~Stack”
free(_a);
_a = nullptr;
_capacity = 0, _top = 0;
}
private:
STDateType* _a;
size_t _capacity;
size_t _top;
};
MyQueue:
class MyQueue {
public:
//编译器默认调用Stack的析构,即使显示析构,调用的依然是Stack的析构
~MyQueue()
{
}
private:
Stack pushst;
Stack popst;
};
- 一个局部域的多个对象,C++规定后定义的先析构。
总结:一般情况下,显示申请了资源,才需要自己实现析构函数,其他情况下基本都不需要自己实现。