C++构造函数、析构函数以及拷贝构造函数



前言

  这篇文章主要讲解C++构造函数、析构函数以及拷贝构造函数。这三个函数都是C++类中默认的成员函数。
在这里插入图片描述


一、构造函数

  构造函数简单理解就是类似于Init()初始化函数,它可以帮助我们完成对象的初始化。对于自己定义的构造函数该怎么处理就怎么处理。

(一)构造函数的特点

  ①构造函数没有返回值。
  ②如果用户没有定义构造含数,那么编译器会自动生成构造函数。
  ③构造函数函数名与类名相同,支持重载。
  ④构造函数一般针对内置类型(char,int,char*,int*......)等不会处理,对自定义类型会调用其默认的构造函数。

  其中默认的构造函数如下图所示,分为编译器自动生成的,无参数的,全缺省的,这三个只会存在一个。
在这里插入图片描述

(二)、构造函数的用法

#include <iostream>
using namespace std;

class B {
private:
	int a;
};

class A {
private:
	int a;
	int b;
	B bb;
};

int main(){
	A a;
	return 0;
}

  我们可以看到这里我们没有自己定义构造函数,我们可以看看系统如何初始化这些值的。下图中我们可以看到,对象a里面的成员变量都是随机值,没有初始化,这就是编译器生成的构造函数一般不对内置对象进行处理。
在这里插入图片描述
  接下来我给类B写了一个无参构造,这里我们再看看编译器是怎么赋值的。

class B {
public:
	B(){
		_a = 1;
	}
private:
	int _a;
	int _b;
	int _c;

};

  这里我们可以看到系统调给A自动生成了构造函数,不对内置类型a,b进行处理,对B用了B的无参构造构造函数,将_a赋值为1,不过其他内置类型还是没有初始化。
在这里插入图片描述

二、析构函数

  析构函数是在对象生命周期结束时候,自动清理一些需要释放的资源,例如malloc,fopen,与数据库的连接等等。
  析构函数能很好帮助我们自动释放该释放的资源,不用像C语言那样忘记资源的释放了。对于自己定义的析构函数该怎么处理就怎么处理。

(一)、析构函数的特点

  ①析构函数没有void,函数名字是~加上类名,例如~A()
  ②析构函数没有参数,且不支持重载。
  ③析构函数在用户没有声明的时候会自动生成,自动调用。
  ④析构函数同构造函数类似,编译器自动生成的析构函数不会对内置类型进行处理,对自定义类型会调用其默认的析构函数。

  代码举例如下:

class A {
public:
	/*~A() {
		cout << a << endl;
		free(a);
		a = NULL;
		cout << a << endl;
		cout << "a释放成功" << endl;
	}*/
	void Create(int n=4) {
		a = (int*)malloc(sizeof(int) * n);
	}
public:
	int *a;
	int b;
	B bb;
};


void fun() {
	A a;
	a.Create();
	a.bb.Create();
	a.~A();
}
int main(){
	fun();
	return 0;
}

  这里我调用a的析构函数,没有自己写析构函数,通过下图可知,a与b的malloc的空间并没有自动释放。
在这里插入图片描述

  一般编译器自动生成的析构函数,也就是我们不用自己写析构函数的情况分为下面两种:
  ①全是内置类型,且内置类型不需要资源释放的那种。(例如:Date类)
  ②有内置内省,且内置类型不需要资源释放的那种,自定义类型对应的类写好了析构函数。(例如:Myqueue)

(二)、析构函数的使用

#include <iostream>

using namespace std;


class B {
public:

	B(){
		_a = 1;
	}
	~B() {
		cout << b << endl;
		free(b);
		b = NULL;
		cout << b << endl;
		cout << "b释放成功" << endl;
	}
	void Create(int n = 4) {
		b = (int*)malloc(sizeof(int) * n);
	}
public:
	int _a;
	int *b;
	int _c;

};

class A {
public:
	~A() {
		cout << a << endl;
		free(a);
		a = NULL;
		cout << a << endl;
		cout << "a释放成功" << endl;
	}
	void Create(int n=4) {
		a = (int*)malloc(sizeof(int) * n);
	}
public:
	int *a;
	int b;
	B bb;
};


void fun() {
	A a;
	a.Create();
	a.bb.Create();
}
int main(){
	fun();
	return 0;
}

  上面代码展示了析构函数的使用,我们可以看看程序结果。我们可以从下图看到,a与b都成功被释放。
在这里插入图片描述

三、拷贝构造函数

  拷贝构造函数是一种特殊的构造函数,他能帮助我们很好复制我们想要复制的对象,不用再输入参数去初始化。对于自己定义的拷贝构造函数该怎么处理就怎么处理。

(一)拷贝构造函数的特点

  ①没有返回值,必须传入引用,例如:A(const A& item),这里没有引用会报错,会引起无限递归。这是因为你传入其他对象时,必须调用拷贝构造函数。
  ②编译器自动生成的拷贝函数会自动对内置类型进行浅拷贝(值拷贝),对于自定义类型会调用其默认的拷贝构造函数。

(二)拷贝构造函数的使用

下面的程序我没有定义拷贝构造,但编译器自动生成了拷贝构造。

#include <iostream>
using namespace std;

class B {
public:

	B(int n = 4){
		_a = 1;
		 b = (int*)malloc(sizeof(int) * n);
		 _c = 2;
	}
	~B() {
		cout << b << endl;
		free(b);
		b = NULL;
		cout << b << endl;
		cout << "b释放成功" << endl;
	}
public:
	int _a;
	int *b;
	int _c;

};
class A {
public:
	A(int a = 4, double b = 3.14, char c = 'a') {
		this->_a = a;
		this->_b = b;
		this->_c = c;
	}
	//A(const A& item) {
	//	this->_a = item._a;
	//	this->_b = item._b;
	//	//this->_b = item._b;
	//	cout << "成功拷贝" << endl;
	//}
public:
	int _a;
	double _b;
	char _c;
	B bb;
};
int main(){
	A a;
	A b(a);
	A c = a;
	return 0;
}

  下图是拷贝构造的结果,我们可以看到编译器将a的值浅拷贝给b,c了。
在这里插入图片描述

(三)浅拷贝缺点

  对于像栈,二叉树的浅拷贝会引来管理上混乱。下图就展示了浅拷贝的缺陷,当你用b删除元素时候,a里面的数组会变而top和size不会变。这时候我们要自己定义拷贝构造函数来实现深拷贝了。
在这里插入图片描述

总结

  文章主要介绍了C++中六个默认成员函数中的三个:构造函数、析构函数以及拷贝构造函数,希望对读者有所帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值