参考:http://www.weixueyuan.net/view/6383.html

总结:

  重载赋值操作符同重载类的是拷贝构造函数的原因是一样,将一个对象拷贝给另一个对象,同时当类中存在指针类型的成员变量时,会出现漏洞。

  赋值操作符“=”可以用来将一个对象拷贝给另一个已经存在的对象。

  如果我们没有在类中显式定义拷贝构造函数,也没有重载赋值操作符,则系统会为我们的类提供一个默认的拷贝构造函数和一个赋值操作符。

  当然,如果在类中并没有包含需要动态分配内存的指针成员变量时,我们使用系统提供的默认拷贝构造函数和赋值操作符也就可以了,无需再自己多此一举的重新定义和重载一遍的。否则必须重载。

赋值操作符“=”可以用来将一个对象拷贝给另一个已经存在的对象。如果我们重新定义了一种新的数据类型,比如说复数类,那么我们就需要重载一下赋值操作符,使之能够满足我们的赋值需求。当然拷贝构造函数同样也会有此功能,拷贝构造函数可以将一个对象拷贝给另一个新建的对象。如果我们没有在类中显式定义拷贝构造函数,也没有重载赋值操作符,则系统会为我们的类提供一个默认的拷贝构造函数和一个赋值操作符。前面在介绍类的相关知识时已经提到,系统为我们提供的默认的拷贝构造函数只是将源对象中的数据一一拷贝给目标对象,而系统为类提供的赋值操作符也是这样的一种功能。

例1:

complex c1(4.3, -5.8);
complex c2;
c2 = c1;
cout<<c1<<endl;
cout<<c2<<endl;

利用前面我们定义的complex类,我们先定义了两个complex类的对象c1和c2,c1对象通过带参构造函数初始化,之后用c1来初始化c2,最后输出这两个复数类对象。在前面定义复数类时我们并未定义拷贝构造函数,也没有重载过赋值操作符,但是在例1中“c2 = c1”并未有语法错误,并且根据函数输出结果也可以得知可以完成我们所需要的赋值操作。这是因为系统默认为类提供了一个拷贝构造函数和一个赋值操作符,而数据一对一的拷贝也满足我们复数类的需求了。

在前面介绍拷贝构造函数时我们提到过这种系统提供的默认拷贝构造函数有一定缺陷,当类中的成员变量包含指针的时候就会有问题,会导致一些意想不到的程序漏洞,此时则需要重新定义一个拷贝构造函数,同样的此时系统提供的赋值操作符也已经不能满足我们的需求了,必须要进行重载。在前面介绍拷贝构造函数那一节中,我们已经详细分析了系统提供的默认拷贝构造函数遇到指针成员变量时带来的风险,其实在直接使用系统默认提供的赋值操作符同样会有此种风险,在此我们将不再重新分析这一问题,而只是将前面的示例再次拿过来,并且在程序中补上赋值操作符重载函数。

例2:

#include<iostream>
using namespace std; class Array
{
public:
Array(){length = ; num = NULL;};
Array(int * A, int n);
Array(Array & a);
Array & operator= (const Array & a);
void setnum(int value, int index);
int * getaddress();
void display();
int getlength(){return length;}
private:
int length;
int * num;
}; Array::Array(Array & a)
{
if(a.num != NULL)
{
length = a.length;
num = new int[length];
for(int i=; i<length; i++)
num[i] = a.num[i];
}
else
{
length = ;
num = ;
}
} //重载赋值操作符
Array & Array::operator= (const Array & a)
{
if( this != &a )
{
delete[] num;
if(a.num != NULL)
{
length = a.length;
num = new int[length];
for(int i=; i<length; i++)
num[i] = a.num[i];
}
else
{
length = ;
num = ;
}
}
return *this;
} Array::Array(int *A, int n)
{
num = new int[n];
length = n;
for(int i=; i<n; i++)
num[i] = A[i];
} void Array::setnum(int value, int index)
{
if(index < length)
num[index] = value;
else
cout<<"index out of range!"<<endl;
} void Array::display()
{
for(int i=; i<length; i++)
cout<<num[i]<<" ";
cout<<endl;
} int * Array::getaddress()
{
return num;
} int main()
{
int A[] = {,,,,};
Array arr1(A, );
arr1.display();
Array arr2(arr1);
arr2.display();
arr2.setnum(,);
arr1.display();
arr2.display();
cout<<arr1.getaddress()<<" "<<arr2.getaddress()<<endl;
arr1 = arr2;
arr1.display();
arr2.display();
arr2.setnum(,);
arr1.display();
arr2.display();
cout<<arr1.getaddress()<<" "<<arr2.getaddress()<<endl;
return ;
}

在这个例子中我们以类成员函数的形式重载了赋值操作符,因为前面已经介绍过该程序了,下面就直接来看主函数。主函数中前半部分和之前介绍拷贝构造函数时是相同的,这个我们也忽略过去。直接从arr1 = arr2语句开始看起。这个语句就会调用类中的操作符重载函数,我们可以将这一语句理解为:
    arr1.operator=( arr2 );
然后就会执行赋值操作符重载函数的函数体中的代码,在该函数体中我们为arr1重新开辟了一个内存空间,因此就可以规避arr1和arr2中的num指向同一块存储区域的风险。如此一来使用系统默认提供的赋值操作符所带来的风险就可以避免了。在这之后的语句中,我们还修改了arr2中的数据,但是这样的修改并没有影响到arr1,可见确实将风险给化解了。

当然,如果在类中并没有包含需要动态分配内存的指针成员变量时,我们使用系统提供的默认拷贝构造函数和赋值操作符也就可以了,无需再自己多此一举的重新定义和重载一遍的。

5.5 C++重载赋值操作符的更多相关文章

  1. C++ 之 重载赋值操作符

    Widget 类中,定义了一个 Bitmap 类型的私有数据成员 -- pb 指针 class Bitmap { ... }; class Widget { private: Bitmap *pb; ...

  2. C++中复制构造函数与重载赋值操作符总结

    前言 这篇文章将对C++中复制构造函数和重载赋值操作符进行总结,包括以下内容: 1.复制构造函数和重载赋值操作符的定义: 2.复制构造函数和重载赋值操作符的调用时机: 3.复制构造函数和重载赋值操作符 ...

  3. C++中复制构造函数与重载赋值操作符

    我们都知道,在C++中建立一个类,这个类中肯定会包括构造函数.析构函数.复制构造函数和重载赋值操作:即使在你没有明确定义的情况下,编译器也会给你生成这样的四个函数.例如以下类:   class CTe ...

  4. Effective C++(10) 重载赋值操作符时,返回该对象的引用(retrun *this)

    问题聚焦: 这个准则比较简短,但是往往就是这种细节的地方,可以提高你的代码质量. 细节决定成败,让我们一起学习这条重载赋值操作符时需要遵守的准则吧. 还是以一个例子开始: Demo // 连锁赋值 x ...

  5. C++重载赋值操作符

    1.C++中重载赋值操作函数应该返回什么? 类重载赋值操作符一般都是作为成员函数而存在的,那函数应该返回什么类型呢?参考内置类型的赋值操作,例如 int x,y,z; x=y=z=15; 赋值行为相当 ...

  6. C++ 数组操作符重载、函数对象分析、赋值操作符

    string类型访问单个字符 #include <iostream> #include <string> #include <sstream> using name ...

  7. C++中的赋值操作符重载和拷贝构造函数

    1,关于赋值的疑问: 1,什么时候需要重载赋值操作符? 2,编译器是否提供默认的赋值操作符? 2,关于赋值的疑问: 1,编译器为每个类默认重载了赋值操作符: 1,意味着同类型的类对象可以相互赋值: 2 ...

  8. 【c++】c++中重载输出操作符,为什么要返回引用

    针对:ostream & operator <<(ostream & os, const ClassType &object) 说明几点: 1.第一个形参为对ost ...

  9. [C++]复制构造函数、赋值操作符与隐式类类型转换

    问题:现有类A定义如下: class A{public:        A(int a)                            //构造函数        {              ...

随机推荐

  1. PC端、移动端的页面适配及兼容处理

    转自 一.关于移动端兼容性 目前针对跨终端的方案,主要分为两大阵营:一套资源Vs两套资源. 第一种是通过响应式或页面终端判断去实现一套资源适配所有终端: 第二种是通过终端判断分别调取两套资源以适配所有 ...

  2. Feign二:复写Feign的默认配置

    Feign二:复写Feign的默认配置 1.在启动文件加入feign注解:@EnableFeignClients FeignApp.java import org.springframework.bo ...

  3. centos7: 将nginx,php-fpm加入开机启动

    1. 自己新建一个脚本,如centnet-service.sh 经过后面的几个步骤后,这个脚本在开机的时候会执行,在这个脚本里面可以写你开机的时候想执行的命令,如启动nginx,phpf-pm等服务 ...

  4. Alibaba Java诊断工具Arthas之快速安装和简单使用

    Alibaba Java诊断工具Arthas简单介绍 : 当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决: 1.这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception ...

  5. linux权限管理之基本权限

    基本权限 UGO ======================================================== 文件权限设置: 可以赋于某个用户或组 能够以何种方式 访问某个文件 ...

  6. Confluence 6 创建一个空间

    在 Confluence 中并不限制你可以创建多少空间.你可以选择为你每一个小组,项目都创建一个空间,或者你也可以将这 2 者混合在一起.所有的这些都基于你的需求来决定的. 每一个 Confluenc ...

  7. memcached的部署

    window下memcached注册服务 cmd:在学习Memcached时,为了模拟分布存储,常常需要建多个Memcached服务,如何建呢,只能使用命令行了 以管理员身份运行cmd,输入如下命令 ...

  8. python记录_day23 正则表达式 re模块

    一. 正则表达式 使用python的re模块之前应该对正则表达式有一定的了解 正则表达式是对字符串操作的一种逻辑公式.我们一般使用正则表达式对字符串进行匹配和过滤. 正则的优缺点: 优点:灵活, 功能 ...

  9. python FileNotFoundError: [WinError 2] 系统找不到指定的文件。

    D:\Test\TestSWP\Scripts\python.exe D:/Test/SWP/TestSWP/chorme/chorme.pyTraceback (most recent call l ...

  10. loj#2353. 「NOI2007」 货币兑换 斜率优化

    题意略 题解:可以列出dp方程\(dp[i]=max(dp[j]*{\frac{a[i]*c[j]+b[i]}{a[j]*c[j]+b[j]}}\),化简可以得到\(\frac{dp[i]}{b[i] ...