文章目录
本文主要搞清楚以下两种写法区别:(看不懂的话可以把
*p_m1
换成 m1
)
- 拷贝构造函数
MyClass m2(*p_m1); // 或:MyClass m2 = *p_m1;
- 等号=赋值运算符重载函数
MyClass m2;
m2 = *p_m1;
先看一段代码:
#include <iostream>
#include <cstdlib>
#include <limits>
#include <string>
using namespace std;class MyClass
{
public:int *ptr;MyClass(){ptr = new int[10];}~MyClass(){delete[] ptr;}MyClass(const MyClass &other) // 拷贝构造函数 //写了这个不用写重载等号代码,调用MyClass m1 = m2;相当于调用了拷贝构造函数{ptr = new int[10];for (int i = 0; i < 10; i++){ptr[i] = other.ptr[i];}}
};int main()
{int *p_int;// MyClass m1;MyClass *p_m1 = new MyClass(); // 创建对象p_int = p_m1->ptr;for (auto i = 0; i < 10; i++){p_m1->ptr[i] = i;}*p_int = 111;for (auto i = 0; i < 10; i++){cout << p_m1->ptr[i] << endl;}MyClass m2 = *p_m1; //没问题 //这个调用了我们上面实现的拷贝构造函数,我把拷贝构造函数注释掉之后就不行了(变成浅拷贝)// MyClass m2; // 段错误 //free(): double free detected in tcache 2 //Aborted (core dumped) /浅拷贝// m2 = *p_m1;// MyClass m2(*p_m1); //没问题 //调用了上面我们实现的拷贝构造函数delete (p_m1);*p_int = 888;for (auto i = 0; i < 10; i++){cout << m2.ptr[i] << endl;}std::cout << "Press ENTER to continue...";std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 读取内容直到用户输入enter键return EXIT_SUCCESS;
}
我用:
MyClass m2 = *p_m1;
能自动调用我们实现的拷贝构造函数,但是:
MyClass m2;
m2 = *p_m1;
却不行?
原因:
这是因为
MyClass m2 = *p_m1;
这种写法是定义并初始化一个新的对象
m2
,在定义时就会调用拷贝构造函数来初始化它。而MyClass m2; m2 = *p_m1;
这种写法是先定义了一个对象
m2
,然后再将*p_m1
赋值给它,这里的赋值操作会调用赋值运算符重载函数,而不是拷贝构造函数。 如果想要使用m2 = *p_m1;
这种写法来调用拷贝构造函数,需要在类中实现赋值运算符重载函数。
另外一点需要注意:
MyClass m2 = *p_m1;
与
MyClass m2(*p_m1);
在用法上是等价的,可以理解为当我们调用MyClass m2 = *p_m1;
时,相当于调用了MyClass m2(*p_m1);
如果我们想要使用MyClass m2; m2 = *p_m1;
这种写法,只需要把等号=赋值运算符重载函数实现一下就好了:
MyClass &operator=(const MyClass &other)
{if (this->ptr != NULL){delete[] this->ptr;}this->ptr = new int[10];for (int i = 0; i < 10; i++){this->ptr[i] = other.ptr[i];}return *this;
}
但是同样,如果只实现了“等号=赋值运算符重载函数”,而“拷贝构造函数”未实现的话,那么 MyClass m2 = *p_m1;
和MyClass m2(*p_m1);
的写法也都是不行了(默认浅拷贝)