您的位置:首页 > 编程语言 > C语言/C++

【C++深度剖析教程14】经典问题解析三之关于赋值的疑问

2018-01-22 00:53 387 查看
今天我们来总结一下,之前所学C++中所遇到的一些经典的问题。

第一个疑问是:

-什么时候需要重载赋值操作符

-编译器是否提供默认的赋值操作?

解答:

*编译器为每个类默认重载了赋值操作符

*默认的赋值操作符仅完成了浅拷贝

*当需要进行深拷贝时,就需要进行赋值操作符的重载

*赋值操作符与拷贝构造函数有相同的存在意义。

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

#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类对象t1内部的指针m_pointer执指向的堆空间为空

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

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

return 0;
}


运行结果为:



以上程序的分析,已经在程序的注释里面了,已经说得很清楚。

总结:

一般性原则:

在需要进行深拷贝的时候,必须进行赋值操作符的重载。

赋值操作符与拷贝构造函数有同等重要的意义。

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

想一起探讨以及获得各种学习资源加我(有我博客中写的代码的原稿):

qq:1126137994

微信:liu1126137994

可以共同交流关于嵌入式,操作系统,C++语言,C语言,数据结构等技术问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息