今天我们来总结一下,之前所学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类对象t2内部的指针m_pointer执指向的堆空间为空
t2 = t1; //因为要实现给t2一个单独的堆空间,也就是实现深拷贝,所以需要上面的赋值操作符的重载以及构造一个拷贝构造函数
t1.print(); //打印的是堆空间的地址值,16进制
t2.print();
return 0;
}
运行结果为:
以上程序的分析,已经在程序的注释里面了,已经说得很清楚。
总结:
一般性原则:
在需要进行深拷贝的时候,必须进行赋值操作符的重载。
赋值操作符与拷贝构造函数有同等重要的意义。
任何文字的说明都无法比真正的代码能让你更加明白其中的原理!!!多动手写~
想一起探讨以及获得各种学习资源加我(有我博客中写的代码的原稿):
qq:1126137994
微信:liu1126137994
可以共同交流关于嵌入式,操作系统,C++语言,C语言,数据结构等技术问题。