【C++】类与对象3:默认成员函数之拷贝构造函数

前言

今天我们来学习默认成员函数中的拷贝构造函数

概念

拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。

特征

  1. 拷贝构造函数是构造函数的一个重载形式
  2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。
    看下面这段代码和注释
void func1(date d)
{
	//d是d1的拷贝
	//调用了拷贝构造
	//cpp规定自定义类型传值传参都会调用拷贝构造
}

void func2(date& rd)
{
	//rd是d1的别名
}

int main()
{
	date d1(2024, 1, 28);
	
	func1(&d1);
	func2(d1);
	return 0;
}

所以根据上面的注释可以看出来 如果拷贝传参是传值的话 就会调用拷贝传参 引发无穷递归
相当于找实习 但实习要求之前有实习经历

  1. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象(内置类型成员)按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。 逐字节拷贝

可以参考下面这段代码进行理解

class Date
{
private:
	// 基本类型(内置类型)
	int _year = 1970;
	int _month = 1;
	int _day = 1;

};
int main()
{
	Date d1;

	// Date类并没有显式定义拷贝构造函数,则编译器会给Date类生成一个默认的拷贝构造函数
	Date d2(d1);
	return 0;
}

d2与d1的值是相同的

小提示:
因为拷贝构造也是一种构造 所以当写了拷贝构造的时候 想调用构造函数有两种方法:

  1. 自己写一个构造函数
  2. 用下面这行代码 表示强制使用默认构造函数
ClassName() = default;
  1. 编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,还需要自己显式实现吗?
    当然像日期类这样的类是没必要的。那么下面的类呢?验证一下试试?
// 这里会发现下面的程序会崩溃掉?这里就需要我们以后讲的深拷贝去解决。
typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 10)
	{
		_array = (DataType*)malloc(capacity * sizeof(DataType));
		if (nullptr == _array)
		{
			perror("malloc申请空间失败");
			return;
		}
		_size = 0;
		_capacity = capacity;
	}
	void Push(const DataType& data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}
	~Stack()
	{
		if (_array)
		{
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	DataType* _array;
	size_t _size;
	size_t _capacity;
};
int main()
{
	Stack s1;
	s1.Push(1);
	s1.Push(2);
	s1.Push(3);
	s1.Push(4);
	Stack s2(s1);
	return 0;
}

注意:类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,则拷贝构造函数是一定要写的,否则就是浅拷贝。

关于深浅拷贝可以看我的另一篇文章
拷贝构造函数典型调用场景:

  • 使用已存在对象创建新对象
  • 函数参数类型为类类型对象
  • 函数返回值类型为类类型对象

结语

关于拷贝构造函数的初步学习到这里就结束了 希望你有收获 我们下次见~~

你可能感兴趣的:(C++知识点,c++,java,javascript)