【C++】经典问题解析三之关于赋值的疑问

来源

https://blog.csdn.net/qq_37375427/article/details/79124030

问题

第一个疑问是:

  • 什么时候需要重载赋值操作符
  • 编译器是否提供默认的赋值操作?

解答:

  • 编译器为每个类默认重载了赋值操作符
  • 默认的赋值操作符仅完成了浅拷贝
  • 当需要进行深拷贝时,就需要进行赋值操作符的重载
  • 赋值操作符与拷贝构造函数有相同的存在意义。

下面我们还是给出一个例子程序来分析:

#include <iostream>
#include <string>

using namespace std;

class Test
{
        int* m_pointer;
public:
        Test()
        {
                m_pointer = NULL;
        }
        Test(int i)
        {
                m_pointer = new int[i];
        }
        void print()
        {
                cout << "m_pointer = " << m_pointer << endl;
        }
        ~Test()
        {
                delete m_pointer;
        }
};

int main()
{
        Test t1 = 1;
        Test t2;
        //t2 = t1;

        t1.print();
        t2.print();

        return 0;
}

运行结果
在这里插入图片描述
上面的程序很简单,我就不多分析了,如果我想将以上的程序注释掉的那一行t2 = t1取消注释加上呢?运行结果如下:
在这里插入图片描述

原因

可以看出,运行结果崩溃,出现了内存错误。
是什么原因呢?
由于我们让t2的堆空间指向了t1,那么再释放堆空间的时候,就需要释放两次,可是我只有一个堆空间,释放两次肯定要出现内存错误的。
在这里插入图片描述

解决

下面我们给出解决办法(进行深拷贝):

#include <iostream>
#include <string>

using namespace std;

class Test
{
    int* m_pointer;
public:
    Test()
    {
        m_pointer = NULL;
    }
    Test(int i)
    {
        m_pointer = new int(i);
    }
    Test(const Test& obj)  //深拷贝函数的构造
    {
        m_pointer = new int(*obj.m_pointer);//先申请一个int型的堆空间,然后给堆空间里加值
                                            //这个值是obj这个对象所指的m_pointer指针所指的值
                                            //,然后让m_pointer再指向这个值的堆空间
    }
    Test& operator = (const Test& obj)  //重载赋值操作符,返回类型必须是引用类型,
                                        //参数必须是const类型的
    {
        if( this != &obj )   //防止自赋值,当前对象的地址与传进来的参数的地址不一样
        {
            delete m_pointer;
            m_pointer = new int(*obj.m_pointer);
        }

        return *this; //返回当前对象的值
    }
    void print()
    {
        cout << "m_pointer = " << hex << m_pointer << endl;
    }
    ~Test()
    {
        delete m_pointer;
    }
};

int main()
{
    Test t1 = 1;   //Test类对象t1内部的指针m_pointer执指向的堆空间的值为1
    Test t2;       //Test类对象t2内部的指针m_pointer执指向的堆空间为空

    t2 = t1;    //因为要实现给t2一个单独的堆空间,也就是实现深拷贝,所以需要上面的赋值操作符的重载以及构造一个拷贝构造函数

    t1.print();   //打印的是堆空间的地址值,16进制
    t2.print();

    return 0;
}

运行结果:
在这里插入图片描述
以上程序的分析,已经在程序的注释里面了,已经说得很清楚。

总结:

一般性原则:

  • 在需要进行深拷贝的时候,必须进行赋值操作符的重载。
  • 赋值操作符与拷贝构造函数有同等重要的意义。

任何文字的说明都无法比真正的代码能让你更加明白其中的原理!!!多动手写~

猜你喜欢

转载自blog.csdn.net/vict_wang/article/details/88781314
今日推荐