C++类和对象(中)——拷贝构造函数

前言

本文承接上文,主要介绍C++语法中的另一个极其重要的成员函数------拷贝构造函数

简要介绍

如果一个构造函数的第一个参数是自身类型的引用,且其余参数均有默认值,那么这个构造函数就是拷贝构造函数,拷贝构造的效果如下

scss 复制代码
int main()
{
	Date d1(2026, 2, 21);
	d1.Print();
	Func1(d1);
	Date d2(d1);
	d2.Print();
	return 0;
}

也就是能用已经初始化的d1初始化d2,这就是拷贝构造的效果

特点

  • 拷贝构造是构造函数重载
  • C++规定传值传参必须调用拷贝构造
  • 拷贝构造的第一个参数必须是类类型对象的引用 如果第一个参数不是引用,只是一个类类型对象,那么就会发生传值传参,调用拷贝构造,然后又会拷贝,因此必须是传引用传参,这样的话问题就迎刃而解了。
  • 如果不希望传进去的实参发生改变,那么可以加一个const从而保护实参
  • 编译器自动生成的拷贝构造函数会对内置类型进行浅拷贝(按字节一个一个拷贝),对于自定义成员会调用其拷贝构造
  • 如果一个类显示实现了析构函数并释放了资源,那么就必须显示写拷贝构造
ini 复制代码
typedef int STDataType;
class Stack
{
public:
	Stack(int n = 4)
	{
		_a = (STDataType*)malloc(sizeof(STDataType) * n);
		if (nullptr == _a)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = n;
		_top = 0;
	}

	// st2(st1)
	Stack(const Stack& st)
	{
		cout << "Stack(const Stack& st)" << endl;

		// 需要对_a指向资源创建同样大的资源再拷贝值
		_a = (STDataType*)malloc(sizeof(STDataType) * st._capacity);
		if (nullptr == _a)
		{
			perror("malloc申请空间失败!!!");
			return;
		}
		memcpy(_a, st._a, sizeof(STDataType) * st._top);
		_top = st._top;
		_capacity = st._capacity;
	}

	void Push(STDataType x)
	{
		if (_top == _capacity)
		{
			int newcapacity = _capacity * 2;
			STDataType* tmp = (STDataType*)realloc(_a, newcapacity *
				sizeof(STDataType));
			if (tmp == NULL)
			{
				perror("realloc fail");
				return;
			}
			_a = tmp;
			_capacity = newcapacity;
		}
		_a[_top++] = x;

	}
	~Stack()
	{
		cout << "~Stack()" << endl;
		free(_a);
		_a = nullptr;
		_top = _capacity = 0;
	}
private:
	STDataType* _a;
	size_t _capacity;
	size_t _top;
};

比如栈这个结构,如果不显示写拷贝构造,那么按照字节拷贝会将st1和st2指向同一块空间,析构的时候会对一块空间析构两次,造成程序崩溃,因此需要自己写。

  • 注意一个易错点:传值返回会产生一个临时对象从而调用拷贝构造,因此应该传引用返回来减少拷贝构造的调用,返回的是返回对象的引用,但是这是如果返回的是当前函数局部域的局部对象,函数结束后对象销毁,这时引用就变成一个野引用了,因此需要保证返回对象的生命周期,当然加一个static也可以
javascript 复制代码
Stack& func2()
{
	static Stack st;//不加static的话出了作用域st就不在了
	return st;
}
int main()
{
	Stack ret = func2();
	return 0;
}

结语

拷贝构造函数到此就介绍完了,希望读者关注下文

相关推荐
MC皮蛋侠客18 小时前
Google Test 单元测试指南
c++·单元测试·google test
艾莉丝努力练剑19 小时前
【Linux:文件】Ext系列文件系统进阶
linux·运维·服务器·c++·文件系统·文件io·ext
basketball61621 小时前
C++ NULL 和 nullptr 区别 以及 nullptr 的核心实现
java·开发语言·c++
Fre丸子_1 天前
自定义文件夹选取功能
c++
思麟呀1 天前
C++工业级日志项目(六)异步日志器
linux·c++·windows
PAK向日葵1 天前
从零实现 Python 虚拟机(二):S.A.A.U.S.O 的总体架构设计
c++·python
无限进步_1 天前
【C++】weak_ptr、循环引用与线程安全
开发语言·数据结构·c++·算法·安全
咩咦1 天前
C++学习笔记30:友元类、内部类和封装
c++·学习笔记·类和对象·封装·内部类·友元类·friend
黄小白的进阶之路1 天前
C++提高编程---3.6 STL-常用容器-queue 容器【P213~P214】
c++
ID_180079054731 天前
小红书评论 API 接口详解与实战开发
java·jvm·c++