首页 > 其他分享 >构造函数和析构函数

构造函数和析构函数

时间:2023-04-29 11:56:09浏览次数:51  
标签:size 函数 int void DataType array 和析构 构造函数

1. 概念引入

在说明构造函数和析构函数的概念之前, 首先看一个例子

下面这段代码是栈经典的应用场景括号匹配

如图, 栈必须先初始化,然后在每一个return false之前都需要销毁栈, 不然就会内存泄漏

这样很繁琐, 而且有些时候很容易忘记写, 所以在C++中添加默认的成员函数,构造函数和析构函数来自动进行初始化和清理工作

2. 6个默认的成员函数

这6个默认的成员函数都是编译器自动生成的, 它们自动进行不同的工作, 如下

本章详细说明其中的两个, 构造函数和析构函数

3. 构造函数

概念及特性

构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象

其特征如下:

  1. 函数名与类名相同
  2. 无返回值
  3. 对象实例化时编译器自动调用对应的构造函数
  4. 构造函数可以重载
  5. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成

特性解析

下面用栈来解析特性:

1. 函数名与类名相同

2. 无返回值

3. 对象实例化时编译器自动调用对应的构造函数

stack.cpp
#include <iostream>
using namespace std;
typedef int DataType;
class Stack
{
public:

	// 函数名与类名相同, 无返回值
	Stack()
	{
		_array = (DataType*)malloc(sizeof(DataType) * 4);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}

		_capacity = 4;
		_size = 0;
	}

	/*void Init()
	{
		_array = (DataType*)malloc(sizeof(DataType) * 4);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}

		_capacity = 4;
		_size = 0;
	}*/

	void Push(DataType data)
	{
		CheckCapacity();
		_array[_size] = data;
		_size++;
	}

	void Pop()
	{
		if (Empty())
			return;
		_size--;
	}

	DataType Top() { return _array[_size - 1]; }
	int Empty() { return 0 == _size; }
	int Size() { return _size; }

	void Destroy()
	{
		if (_array)
		{
			free(_array);
			_array = NULL;
			_capacity = 0;
			_size = 0;
		}
	}

private:
	void CheckCapacity()
	{
		if (_size == _capacity)
		{
			int newcapacity = _capacity * 2;
			DataType* temp = (DataType*)realloc(_array, newcapacity * sizeof(DataType));
			if (temp == NULL)
			{
				perror("realloc申请空间失败!!!");
				return;
			}
			_array = temp;
			_capacity = newcapacity;
		}
	}
private:
	DataType* _array;
	int _capacity;
	int _size;
};

int main()
{
	Stack s; // 自动调用构造函数
	//s.Init();
	s.Push(1);
	s.Push(2);
	s.Push(3);
	s.Push(4);
}

4. 构造函数可以重载

构造函数支持重载是因为可能会有多种初始化的场景

5. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成

#include <iostream>
using namespace std;

class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print() // 3. void Print(Date* this)
	{
		cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
	}
private:
	int _year;     // 年   
	int _month;    // 月
	int _day;      // 日
};
int main()
{
	Date d1, d2;
	//d1.Init(2022, 1, 11);
	//d2.Init(2023, 4, 28);
	d1.Print();
	//d1.Print(&d1);
	//d2.Print();
	//d2.print(&d2);
}

从图中, 发现编译器默认生成的构造函数好像并没有进行初始化, 依旧是随机值

这是因为C++标准规定内置类型(char, int...)不做处理(置0), 但是自定义类型(class, struct)会去调用它的默认构造函数处理初始化, 如下图

test.cpp
 #include <iostream>
using namespace std;
typedef int DataType;
class Stack
{
public:
	/*Stack(DataType* a, int n)
	{
		cout << "Stack(DataType* a, int n)" << endl;
		_array = (DataType*)malloc(sizeof(DataType) * n);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}
		memcpy(_array, a, sizeof(DataType) * n);

		_capacity = n;
		_size = n;
	}*/

	Stack(int capacity = 4)
	{
		cout << "Stack(int capacity = 4)" << endl;
		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}

		_capacity = capacity;
		_size = 0;
	}

	/*void Init()
	{
		_array = (DataType*)malloc(sizeof(DataType) * 4);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}

		_capacity = 4;
		_size = 0;
	}*/

	void Push(DataType data)
	{
		CheckCapacity();
		_array[_size] = data;
		_size++;
	}

	void Pop()
	{
		if (Empty())
			return;
		_size--;
	}

	DataType Top() { return _array[_size - 1]; }
	int Empty() { return 0 == _size; }
	int Size() { return _size; }

	/*void Destroy()
	{
		if (_array)
		{
			free(_array);
			_array = NULL;
			_capacity = 0;
			_size = 0;
		}
	}*/

	~Stack()
	{
		cout << "~Stack()" << endl;
		if (_array)
		{
			free(_array);
			_array = NULL;
			_capacity = 0;
			_size = 0;
		}
	}

private:
	void CheckCapacity()
	{
		if (_size == _capacity)
		{
			int newcapacity = _capacity * 2;
			DataType* temp = (DataType*)realloc(_array, newcapacity * sizeof(DataType));
			if (temp == NULL)
			{
				perror("realloc申请空间失败!!!");
				return;
			}
			_array = temp;
			_capacity = newcapacity;
		}
	}
private:
	DataType* _array;
	int _capacity;
	int _size;
};

class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print() // 3. void Print(Date* this)
	{
		cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
	}
private:
    // 内置类型
	int _year;     // 年   
	int _month;    // 月
	int _day;      // 日
    // 自定义类型
	Stack st;
};
int main()
{
	Date d1, d2;
	//d1.Init(2022, 1, 11);
	//d2.Init(2023, 4, 28);
	d1.Print();
	//d1.Print(&d1);
	//d2.Print();
	//d2.print(&d2);
}

在C++11中, 为了弥补内置类型成员不初始化的缺陷,打了补丁 (内置类型成员变量在类中声明时可以给默认值)

class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print() // 3. void Print(Date* this)
	{
		cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
	}
private:
	// 不是初始化, 而是默认的缺省值
	int _year = 1;     
	int _month = 1;    
	int _day = 1;      
};
int main()
{
	Date d1, d2;
	d1.Print();
}

构造函数的调用

构造函数的调用与普通函数不同, 如下例

class Date
{
public:
	Date()
	{
		_year = 1;
		_month = 1;
		_day = 1;
	}
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print() // 3. void Print(Date* this)
	{
		cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
	}
private:
	// 不是初始化, 而是缺省值(默认值)
	int _year = 1;     
	int _month = 1;    
	int _day = 1;      
};
int main()
{
	Date d1(2222,2,2); // 构造函数的调用
	d1.Print();
}

默认的构造函数

编译器默认生成的构造函数,无参的构造函数和全缺省的构造函数都称为默认构造函数,且默认构造函数只能有一个

类实例化对象时会自动调用构造函数, 但是由于有两个默认的构造函数, 所以报错

4. 析构函数

概念及特性

析构函数与构造函数功能相反, 完成对象中资源的清理工作

注意: 析构函数不是完成对对象本身的销毁而是对象中的资源, 局部对象本身的销毁工作是由编译器完成的

特性如下:

  1. 析构函数名是在类名前加上字符 ~
  2. 无参数无返回值类型
  3. 对象生命周期结束时,C++编译系统系统自动调用析构函数
  4. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载
  5. 关于编译器自动生成的析构函数,是否会完成一些事情呢?下面的程序我们会看到,编译器生成的默认析构函数,对自定类型成员调用它的析构函数

解析特性

下面还是用栈来解析这些特性:

析构函数名是在类名前加上字符 ~

无参数无返回值类型

对象生命周期结束时,C++编译系统系统自动调用析构函数

stack.cpp
 #include <iostream>
using namespace std;
typedef int DataType;
class Stack
{
public:

	// 函数名与类名相同, 无返回值
	Stack()
	{
		_array = (DataType*)malloc(sizeof(DataType) * 4);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}

		_capacity = 4;
		_size = 0;
	}

	/*void Init()
	{
		_array = (DataType*)malloc(sizeof(DataType) * 4);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}

		_capacity = 4;
		_size = 0;
	}*/

	void Push(DataType data)
	{
		CheckCapacity();
		_array[_size] = data;
		_size++;
	}

	void Pop()
	{
		if (Empty())
			return;
		_size--;
	}

	DataType Top() { return _array[_size - 1]; }
	int Empty() { return 0 == _size; }
	int Size() { return _size; }

	// 析构函数
	~Stack()
	{
		if (_array)
		{
			free(_array);
			_array = NULL;
			_capacity = 0;
			_size = 0;
		}
	}
	/*void Destroy()
	{
		if (_array)
		{
			free(_array);
			_array = NULL;
			_capacity = 0;
			_size = 0;
		}
	}*/

private:
	void CheckCapacity()
	{
		if (_size == _capacity)
		{
			int newcapacity = _capacity * 2;
			DataType* temp = (DataType*)realloc(_array, newcapacity * sizeof(DataType));
			if (temp == NULL)
			{
				perror("realloc申请空间失败!!!");
				return;
			}
			_array = temp;
			_capacity = newcapacity;
		}
	}
private:
	DataType* _array;
	int _capacity;
	int _size;
};

int main()
{
	Stack s; // 对象实例化时编译器自动调用对应的构造函数
	//s.Init();
	s.Push(1);
	s.Push(2);
	s.Push(3);
	s.Push(4);
	//s.Destroy();
}

 

标签:size,函数,int,void,DataType,array,和析构,构造函数
From: https://www.cnblogs.com/xumu11291/p/17362198.html

相关文章

  • 数据库函数
    常用函数数据函数字符串函数日期和时间函数系统函数题目介绍实现数据加密常用函数1.数据函数SELECTABS(-8);/*绝对值*/SELECTCEILING(9.4);/*向上取整*/SELECTFLOOR(9.4);/*向下取整*/SELECTRAND();/*随机数,返回一个0-1之间的随机数*/SELECT......
  • C语言函数大全-- s 开头的函数(2)
    C语言函数大全本篇介绍C语言函数大全--s开头的函数(2)1.setlinestyle1.1函数说明函数声明函数功能voidsetlinestyle(intlinestyle,unsignedupattern,intthickness);设置当前绘图窗口的线条样式、线型模式和线条宽度参数:linestyle:线条样式,取值范围......
  • 在Amazon SageMaker平台上使用Docker部署Lambda函数
    目录1相关工具2准备工作3构建镜像4配置ECR并推送镜像5使用镜像创建Lambda函数6参考信息1相关工具AWSCLIAWSCommandLineInterface(AWSCLI)是一个命令行工具,我们可以用它在终端中与AWS服务进行交互文档:什么是AWSCommandLineInterface?-AWSCommandLineI......
  • 证明 一个 和 三角函数 有关 的 函数 单调递减
    吧主 @黎合胜  只会出物理题,  数学题还得我来,  嘿嘿 。 数学吧  《三角函数问题》     https://tieba.baidu.com/p/8384790600   。  ......
  • c++中的构造函数
    C++中的构造函数可以分为一下几种:默认构造函数初始化构造函数(有参数)拷贝构造函数移动构造函数(move和右值引用)委托构造函数转换构造函数#include<iostream>usingnamespacestd;classStudent{public:Student(){//默认构造函数,没有参数this->age=20......
  • MFC-SetWindowLong设置窗口样式、窗口标识符ID、处理函数
     修改样式LONGStyles;Styles=GetWindowLong(hWnd4,GWL_STYLE);//获取原窗口风格/*参数1:HWNDhWnd窗口句柄参数2:intnIndex改变窗口上的何种属性*/LONGl=SetWindowLong(hWnd4,GWL_STYLE,Styles|LVS_REPORT);//设置新的......
  • MFC-GetWindowLong获取窗口样式、窗口标识符ID、处理函数
     获取窗口样式LONGStyles=GetWindowLong(hWnd4,GWL_STYLE);//获取窗口风格/*参数1:HWNDhWnd窗口句柄参数2:intnIndex改变窗口上的何种属性窗口属性包括窗口的样式(GWL_STYLE)、扩展样式(GWL_EXSTYLE)、窗口函数、窗......
  • 正余弦函数
    #define_CRT_SECURE_NO_WARNINGS1#include<stdio.h>#include<math.h>#include<Windows.h>     //=清屏#definepi3.1415926      //定义圆周率intmain(){ inti,j; doublea,b; while(1) { printf("正弦函数请输入‘1’,余弦函数请输入‘2......
  • C++中函数重载和重写的区别是什么?
    函数重载:利用命名矫正(namemangling)技术,在编译时把函数名加上参数的首字母来区分同名函数。需要满足3个条件:1.同一个作用域下2.函数名相同3.函数参数类型不同,参数个数不同,参数顺序不同 示例:1......
  • sql中的流程函数
    流程函数--if相关selectempno,ename,sal,if(sal>=2500,'高薪','底薪')as'薪资等级'fromemp;--if-else双分支结构selectempno,ename,sal,comm,sal+ifnull(comm,0)fromemp;--如果comm是null,那么取值为0--单分支--case相关:--case等值判断selectempno,ename......