目录
1.引言
1.不写编译器自动生成的拷贝构造,对内置类型浅拷贝/值拷贝
2.对自定义类型,调用它的拷贝构造
3.拷贝构造也是构造函数,是它的一个重载形式
4.拷贝构造只有一个参数,且必须使用引用传参
5.用于初始化一个对象
typedef int DataType;
class Stack
{
public:
Stack(size_t capacity = 4)
{
cout << "Stack(size_t capacity = 10)" << endl;
_array = (DataType*)malloc(capacity * sizeof(DataType));
if (_array == nullptr)
{
perror("malloc申请空间失败");
exit(-1);
}
_size = 0;
_capacity = capacity;
}
Stack(const Stack& st)
{
cout << "Stack(const Stack& st)" << endl;
_array = (DataType*)malloc(sizeof(DataType)*st._capacity);
if (_array == nullptr)
{
perror("malloc申请空间失败");
exit(-1);
}
memcpy(_array, st._array, sizeof(DataType)*st._size);
_size = st._size;
_capacity = st._capacity;
}
~Stack()
{
cout << "~Stack()" << endl;
if (_array)
{
free(_array);
_array = nullptr;
_capacity = 0;
_size = 0;
}
}
private:
DataType *_array;
size_t _size;
size_t _capacity;
};
2.如何使用拷贝构造
int main()
{
Stack st1;
Stack st2(st1);
Stack st3 = st1;
return 0;
}
运行结果 :
3.什么时候一定要写拷贝构造?
实现了析构函数释放空间,就要实现拷贝构造
比如这里的栈就必须要写
3.1重复析构导致的问题
1.插入删除数据会相互影响
2.析构两次程序崩溃
4.什么时候会调用拷贝构造
用Date的例子
Date Test(Date date)
{
Date tmp(Date);
return tmp;
}
这里会调用两次拷贝构造分别是传值传参和传值返回
5.默认生成的构造,析构,拷贝构造
class Queue
{
private:
Stack _pushST;
Stack _popST;
int _size = 0;
};
int main()
{
Queue q1;
Queue q2(q1);
return 0;
}
运行结果如下:
注意:析构的顺序是后进先出的原则,所以析构顺序是:q2._popST, q2._pushST, q1._popST, q1.push_ST
6.为什么必须是传引用传参
条件1:编译器是会自己生成一个拷贝构造,这个拷贝构造是浅拷贝(值拷贝),只是单纯的赋值
条件2:用一个自定义类型去初始化另一个自定义类型时候会调用拷贝构造
那么如果是传值传参,他就会去调用拷贝构造 ,好 现在去调用拷贝构造,但是这个拷贝构造里的参数 是一个传值传参,他又要去调拷贝构造,所以无穷递归
7. 拷贝构造里最好带上const
Stack(const Stack& st)
1.可以让原本const修饰的Stack被拷贝构造,成为右操作数
2.防止左操作数和右操作数写反,导致的数据异常
例
//1
int main()
{
const Stack st1();
Stack st2(st1);//这里会报错
//因为在执行拷贝构造时候出现权限的放大
return 0;
}
//2
Stack(Stack& st)
{
//...
st._size = _size;
st._capacity = _capacity;
}