C++“拷贝构造函数”与“等号=赋值运算符重载函数”的使用注意事项

文章目录


本文主要搞清楚以下两种写法区别:(看不懂的话可以把 *p_m1换成 m1

  1. 拷贝构造函数
MyClass m2(*p_m1);	// 或:MyClass m2 = *p_m1;
  1. 等号=赋值运算符重载函数
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);的写法也都是不行了(默认浅拷贝)

猜你喜欢

转载自blog.csdn.net/Dontla/article/details/130463480