[C++]拷贝构造函数使用规则以及注意事项
目录
一、拷贝构造函数使用规则
二、拷贝构造函数注意事项
1、浅拷贝
2、深拷贝
三、拷贝构造函数总结
四、演示代码
一、拷贝构造函数使用规则
1、拷贝构造函数时构造函数一种重载形式。
2、参数类型是类类型对象的引用,传入对象时,函数参数除了是类类型对象的引用,不能传值调用,会引发无穷递归,并且需要加入const来进行修饰,防止对象内容发生改变。
3、编译器会默认生成拷贝构造函数,如果自定义拷贝构造函数,编译器不会生成默认拷贝构造函数。
二、拷贝构造函数注意事项
1、浅拷贝
如果未显示定义拷贝构造函数,编译器会生成默认的拷贝构造函数,对于自定义类型完成值拷贝,对于自定义类型调用自己的拷贝构造。
如果有些类有申请资源,就需要自定义拷贝构造函数完成深拷贝,简单的使用编译器默认生成的拷贝构造函数只是完成浅拷贝,容易引起程序运行崩溃。

图片内容解释
1、创建s1对象调用了构造函数,在构造函数中,默认申请了10个int元素的空间,然后调用s1.push插入4个元素,分别是1 2 3 4。
2、调用 Stack s2(s1),调用编译器默认生成的拷贝构造函数,默认生成的拷贝构造函数是完成值拷贝,即将s1中的内容拷贝给s2,所以s1和s2的_a指向了同一块空间。
3、程序退出时,s2先销毁,s1后销毁。所以先调用s2的析构函数将指向的空间释放,但是s1销毁时同样会调用s1的析构函数释放所指的空间,这就导致s1,s2所指的同一块空间两次释放,引起程序崩溃,这就是默认使用编译器生成的拷贝构造函数完成浅拷贝引发的问题,因此需要用深拷贝来解决这个问题
2、深拷贝
对于有涉及申请资源的类,拷贝构造函数中需要深拷贝需要重新开辟一块空间给新对象,避免析构时同一块空间多次释放。

三、拷贝构造函数总结

1、拷贝构造函数时构造函数重载的一种形式
2、拷贝构造函数的参数只有一个必须是类类型的对象的引用,如果使用传值方式编译器会报错,而且会引发无穷拷贝构造函数递归调用。
3、拷贝构造函数参数要用const 进行修饰,防止传入的对象内容发生改变。
4、如果未显示写拷贝构造函数,编译器会默认生成拷贝构造函数,对于内置类型会完成值拷贝(浅拷贝),对于自定义类型会去调用自己的拷贝构造函数。
5、涉及到深浅拷贝的问题需要自定义拷贝构造函数,例如:类对象在堆区malloc了内存空间,拷贝构造函数需要完成深拷贝。
6、拷贝构造函数的调用场景是:用已存在的对象创建新对象,函数参数类型是类类型的对象以及返回值类型是类类型对象。
四、演示代码
#include<iostream>
using namespace std;class Stack
{
public://全缺省构造函数Stack(int capacity = 10){cout << this << endl;_a = (int*)malloc(sizeof(int) * capacity);if (_a == nullptr){perror("malloc fail!");return;}_top = 0;_capacity = capacity;}//拷贝构造函数Stack(const Stack& st){//实现深拷贝cout << this << endl;_a = (int*)malloc(sizeof(int) * st._capacity);if (_a == nullptr){perror("malloc fail!");return;}memcpy(_a, st._a, sizeof(int) * st._top);_top = st._top;_capacity = st._capacity;}//插入数据void Push(int x){_a[_top] = x;_top++;}//析构函数~Stack(){if (_a){free(_a);_a = nullptr;_top = 0;_capacity = 0;}}
private:int* _a=nullptr;int _top=0;int _capacity=0;
};int main()
{Stack s1;s1.Push(1);s1.Push(2);s1.Push(3);s1.Push(4);Stack s2(s1);cout << "s1地址:" << &s1 << endl;cout << "s2地址:" << &s2 << endl;return 0;
}
