1 概念
在现实生活中,可能存在一个与你一样的自己,我们称其为双胞胎。那在创建对象时,可否创建一个与已存在对象一某一样的新对象呢?

那在创建对象时,可否创建一个与已存在对象一某一样的新对象呢?
拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。
2 特征
拷贝构造函数也是特殊的成员函数,其特征如下:
1. 拷贝构造函数是构造函数的一个重载形式。
2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。

为什么会出现错误呢,我们知道形参是实参的一份临时拷贝,当我们创建形参的时候,就要对实参进行拷贝,而编译器对于自定义类型调用其拷贝构造函数(对于内置类型,编译器会直接拷贝),因此当我们创建形参的时候就要调用拷贝构造,调用拷贝构造的时候就会创建形参 ...... ........因此形成无穷递归调用。

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

注意:在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定
 义类型是调用其拷贝构造函数完成拷贝的。
4. 编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,但是对于开辟内存的类我们还能这样吗?
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;
}答案是:不能!!
对于日期类的拷贝,没有指针可以浅拷贝(按照字节进行拷贝)。但是对于有指针的类,我们浅拷贝的话,就会造成两个指针指向同一空间,在运行过程会对同一块内存多次初始化和销毁。


注意:类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请
 时,则拷贝构造函数是一定要写的,否则就是浅拷贝。
5. 拷贝构造函数典型调用场景:
        使用已存在对象创建新对象
         函数参数类型为类类型对象
         函数返回值类型为类类型对象


        为了提高程序效率,一般对象传参时,尽量使用引用类型,返回时根据实际场景,能用引用
 尽量使用引用。



















