拷贝构造函数
使用场景:
- 在用一个对象创建一个新的对象时会采用拷贝构造函数
- 对象作为函数的返回值以值的方式从函数返回
对象作为函数参数,以值的传递方式传给函数
#include<iostream>
using namespace std;
/*
* 使用场景:
1.使用一个已经存在的对象创建一个新的对象
2.对象作为函数的返回值以值的方式从函数返回
3.对象作为函数参数,以值的传递方式传给函数
*/
/*
5点
1.拷贝构造的使用场景
2.匿名对象
3.拷贝构造的参数为什么要用引用
4.深拷贝和浅拷贝
5.关键字explicit
*/
class A {
int num;
public:
A(int num) {
this->num = num;
}
A(const A& other) {//当构造函数前加一个关键字‘explicit’时 就不能用A b = a,就应该写成A b(a);
//加一个&参数变成引用类型 此时不会发生拷贝 避免先入拷贝构造循环
this->num = other.num;
cout << "拷贝构造" << endl;
}
~A() { cout << "析构函数" << endl; }
};
void fun(A a) {}
A fun() {
A a(3);
return a;//返回时运用拷贝构造 如果没有值接收 则创建一个匿名对象 接收
}
int main() {
A(2);//创建了一个匿名对象,匿名对象只存在当前行,当前行结束就销毁,即析构
cout << 1 << endl;
A a(3);
A b = a;//编译器内部转换成A b(a);的格式
A c = 2;//编译器内部转换成A c(2);的格式
fun(a);
A d = fun();
return 0;
}
深拷贝和浅拷贝
- 对象中含有指针类型的成员变量时需要用深拷贝构造,否则用浅拷贝构造
- 编译器默认的拷贝构造函数是浅拷贝构造
- 如果对象中含有指针变量确实用了前拷贝构造,那么会导致两个指针变量指向同一块地址空间被释放两次,编译器报错
- 浅拷贝和深拷贝的区别在于两个指针变量指向的是一块空间还是指向不同的空间,如果没有创建内存的操作就是浅拷贝,否则是深拷贝。
#include<iostream>
using namespace std;
/*
对象中含有指针类型的成员变量时需要深拷贝构造,否则浅拷贝
编译器默认的拷贝构造函数是浅拷贝构造函数
如果对象中含有指针变量却使用了浅拷贝构造,那么会导致两个指针变量指向同一块地址空间,那么在对象释放时会导致一块空间释放两次,编译器报错
浅拷贝和深拷贝的区别在于两个指针变量指向的是一块空间还是指向不同的空间,如果没有创建内存的操作就是浅拷贝否则是深拷贝
*/
class Test {
int num;
int* p = nullptr;
public:
Test() { cout << "无参构造" << endl; }
Test(int n) {
cout << "有参构造" << endl;
num = n;
if (num > 0)p = (int*)malloc(sizeof(int) * num);//或者p = new int*[num]
}
Test(const Test& other) {
cout << "拷贝构造" << endl;
this->num = other.num;
//if (other.p) this->p = other.p;浅拷贝
if (num > 0) {
this->p = (int*)malloc(sizeof(int) * num);
}
}
~Test() {
if (p) {
free(p);
p = nullptr;
}
cout << "析构函数" << endl;
}
};
Test fun() {
Test t;
return t;
}
int main() {
Test t(3);
Test t1(t);
return 0;
}
-
有几点需要注意:
-
返回值是以值的形式返回时,在函数调用部分如果有对象接收会通过拷贝构造传递给对象,如果没有对象接收 也会拷贝一个匿名对象,但是这个匿名对象只存在于当前行
-
拷贝构造的参数需要引用,因为如果不是引用会陷入拷贝构造的循环中
-
如果对象中含有指针类型的成员变量,则需要用到深拷贝构造,否则前拷贝构造
-
如果在拷贝构造函数前加入一个关键字explicit则不能使用隐式调用
例如以下代码:
class A{
int a;
public :
A(int a){this->a = a;}
A(const A& other){this->a = other.a;}
//explicit A(const A& other){this->a = other.a;} 这种情况不能隐式调用
}
int main(){
A a(5);
A b = a;//隐式调用相当于A b(a);
return 0;
}