1、重载赋值运算符=

赋值运算符用于同类对象间的相互赋值。赋值运算符只能被重载为类的非静态成员函数,不能重载为友元函数和普通函数。

对于用户自定义的类而言,如果没有重载赋值运算符,那么C++编译器会为该类提供一个默认的重载赋值运算符成员函数。

默认赋值运算符的工作方式是按位对拷,将等到右边对象的非静态成员拷贝给等号左边的对象。

重载赋值运算符函数必须是public的,否则会编译错误,因为用户定义了重载赋值运算符函数,编译器就不会提供默认的。

在类中重载的赋值运算符函数不能被继承!

通常情况下编译器提供的默认重载赋值运算符函数能够解决对象间赋值的问题,但是当类中含有指针数据成员时,容易引起指针悬挂的问题,

所以这种情况下有必要进行赋值运算符重载。

举一个例子,下面的程序使用默认的重载赋值运算符函数,在Linux下运行会检测到double free的问题,其实还有一个内存泄漏的问题(使用valgrind工具检测),即指针悬挂。

原因是对象之间赋值时,对象s2的指针成员pstr的值被赋值成对象s1的指针成员pstr的值,这时对象s2中申请的堆空间就被遗忘了,程序结束时没有人释放,

同时s2对象析构时,释放的是所s1申请的堆空间,s1对象析构时,就产生了2次释放的问题。

#include <cstring>
#include <iostream>
using namespace std; class MyString
{
public:
MyString(const char* str){count = strlen(str);pstr = new char[count+];strcpy(pstr, str);}
~MyString(){delete []pstr;}
void display(void){cout<<pstr<<endl;}
private:
char *pstr;
int count;
};
int main(void)
{
MyString s1("Hello");s1.display();
MyString s2("World");s2.display(); s2 = s1;s2.display();//glibc detected : double free or corruption return ;
} /** valgrind 结果
Invalid free() / delete / delete[] / realloc()

LEAK SUMMARY:
  definitely lost: 6 bytes in 1 blocks

**/  

下面使用自定义赋值运算符重载来解决内存泄漏和2次释放的问题。

#include <cstring>
#include <iostream>
using namespace std; class MyString
{
public:
MyString(const char* str){count = strlen(str);pstr = new char[count+];strcpy(pstr, str);}
~MyString(){delete []pstr;}
void display(void){cout<<count<<":"<<pstr<<endl;}
//operator overload : =
MyString& operator=(MyString& ref)
{
if (this != &ref)
{
delete []pstr;
count = ref.count;
pstr = new char[count+];
strcpy(pstr, ref.pstr);
}
return (*this);
} private:
char *pstr;
int count;
};
int main(void)
{
MyString s1("Hello");s1.display();
MyString s2("World");s2.display(); s2 = s1;s2.display();//OK return ;
}

2、重载下标运算符[]

下标运算符只能被重载为类的非静态成员函数,不能重载为友元函数和普通函数。

由于[]既可以作为左值又可以作为右值,所以重载下标运算符函数通常返回引用。

于其他运算符重载有一点不同的是:[]重载的功能是多样的,完全取决于用户的定义,但是通常是数组相关的。

重载的下标运算符函数只能有一个参数,即使用的方式只能是 Aclss[para],不能没有参数或者是Aclss[para1, para2]多参数的形式。

例子:通过重载下标运算符,可以很方便的取得和修改类中的数组。

#include <iostream>
using namespace std; class MyArrary
{
public:
MyArrary(int a1,int a2,int a3, int a4){arr[]=a1;arr[]=a2;arr[]=a3;arr[]=a4;} //operator overload : []
int& operator[](int num)//返回引用才能进行赋值操作
{
if ((num < ) || (num > ))
{
cout <<"error:";
num = ;
}
return arr[num];
} private:
int arr[];
}; int main(void)
{
MyArrary ma(,,,);
cout << ma[]<<endl; //取值
ma[] = ; //赋值
cout << ma[]<<endl;
return ;

3、重载括号运算符()

括号运算符只能被重载为类的非静态成员函数,不能重载为友元函数和普通函数。

由于()既可以作为左值又可以作为右值,所以重载括号运算符函数通常返回引用。

重载括号运算符函数的参数个数没有限制,甚至没有参数都可以。

例子:通过重载括号运算符,可以很方便的取得和修改类中的数组。

#include <iostream>
using namespace std; class DArrary
{
public:
DArrary(int num){int i = ; for (i = ; i< ;i++) arr[i/][i%] = num++;}
void display(void){int i = ;for (i = ; i< ;i++) cout<<arr[i/][i%]<<" ";cout<<endl;} //operator overload : () Multiple Parameters
int& operator()(int a, int b)
{
return arr[a][b];
} //operator overload : () Singal Parameter
int& operator()(int a)
{
return arr[a/][a%];
}
//operator overload : () None Parameter
int& operator()(void)
{
return arr[][];
}
private:
int arr[][];
};
int main(void)
{
DArrary arr();arr.display();
cout << arr(,) << endl; //取值
cout << arr(,) << endl; //取值
arr(,) = ; //赋值
arr(,) = ; //赋值
cout << arr(,) << endl;
cout << arr(,) << endl; cout << arr() << endl; //取值
arr() = ; //赋值
cout << arr() << endl; cout << arr() << endl;
arr() = ;
arr.display();
return ;
}

C++运算符重载——重载特殊运算符的更多相关文章

  1. C++ Primer : : 第十四章 : 重载运算符与类型转换之类型转换运算符和重载匹配

    类型转换运算符 class SmallInt { public: SmallInt(int i = 0) : val(i) { if (i < 0 || i > 255) throw st ...

  2. C++运算符重载——重载二元运算符

    1.重载二元操作符的方法 二元运算符又称为双目运算符,即需要2个操作数的运算符,例如 + - * / 等. 运算符重载可以分为3种方式:类的非静态成员函数.类的友元函数.普通函数. 例如有 2 个操作 ...

  3. C++运算符重载——重载一元运算符

    0.重载一元操作符的方法 一元运算符即只需要一个操作用的运算符,如取地址运算符(&).复数(-).自减(--).自加(++)等. 运算符重载可以分为3种方式:类的非静态成员函数.类的友元函数. ...

  4. C++重载流插入运算符和流提取运算符【转】

    C++的流插入运算符“<<”和流提取运算符“>>”是C++在类库中提供的,所有C++编译系统都在类库中提供输入流类istream和输出流类ostream.cin和cout分别是 ...

  5. [置顶] C++基础之六:运算符的重载

    网上太多有关运算符的重载了,但是写的太过的详细,不适合新手入门,特别是那什么++和--的前增量后增量重载,一元二元运算符重载,特殊运算符,下标运算符,new和delete,甚至是指针运算符的重载,吓退 ...

  6. C++运算符重载——输入/输出运算符

    为了与IO标准库一致,重载输入输出运算符函数的第一个行参应该是流的引用,第二个行参是对象的引用. 如果重载为类的成员函数,第一个行参应该是对象的引用,第二个行参是流的引用. 使用方式是 ClassOb ...

  7. 【转】C++对成员访问运算符->的重载

    运算符->的重载比较特别,它只能是非静态的成员函数形式,而且没有参数. 1.如果返回值是一个原始指针,那么就将运算符的右操作数当作这个原始指针所指向类型的成员进行访问: 2.如果返回值是另一个类 ...

  8. C++ 重载运算符和重载函数

    C++ 重载运算符和重载函数 C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载. 重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是 ...

  9. C++解析七-重载运算符和重载函数

    重载运算符和重载函数C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载.重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列 ...

随机推荐

  1. R语言实战读书笔记2—创建数据集(上)

    第二章 创建数据集 2.1 数据集的概念 不同的行业对于数据集的行和列叫法不同.统计学家称它们为观测(observation)和变量(variable) ,数据库分析师则称其为记录(record)和字 ...

  2. [2016-06-28]dhclient命令的进程没杀死,导致不断在向DHCP服务器获取IP

    # Date:2016-06-28 # 问题:主机的配置文件/etc/sysconfig/network-scripts/ifcfg-eth0 已经配置好了静态的IP. 但隔几分钟主机的IP就自己变化 ...

  3. MATLAB GUI程序设计中ListBox控件在运行期间消失的原因及解决方法

    在运行期间,ListBox控件突然消失,同时给出如下错误提示: Warning: single-selection listbox control requires that Value be an ...

  4. Log4J配置文件说明

    Log4J的配置文件(Configuration File)就是用来设置记录器的级别.存放器和布局的,它可接key=value格式的设置或xml格式的设置信息.通过配置,可以创建出Log4J的运行环境 ...

  5. SQL SERVER完整、差异和事务日志备份及还原(脚本和GUI实现) [原创]

    一.完整备份.差异备份和事务日志备份的脚本 --完整备份数据库 BACKUP DATABASE Test_Bak TO DISK = 'E:\20150609_75\bak\Test_bak_full ...

  6. Shell常用操作

    1.读取配置文件中的jdbc_url参数的值($InputParamFile为待读取的目标文件绝对路径) jdbc_url=`grep "jdbc_url" $InputParam ...

  7. 待验证的一些IOS问题

    1.images.assert中的图片格式必须是png.(jpg格式的图片不行)

  8. POSⅨ thread

    POSⅨ thread 简称为pthread,Posix线程是一个POSⅨ标准线程.该标准定义 内部API创建和操纵线程. 编辑本段作用 线程库实行了POSIX线程标准通常称为pthreads.POS ...

  9. 【BZOJ】【4034】【HAOI2015】T2

    树链剖分/dfs序 树上单点修改+子树修改+链查询 其实用dfs序做也可以…… 其实树链剖分就是一个特殊的dfs序嘛= =所以树链剖分也可以搞子树-(Orz ZYF) 至于为什么……你看在做剖分的时候 ...

  10. [剑指OFFER] 数组中的逆序对

    题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数.     分析:利用归并排序的思想,分成2部分,每一部分按照从大到 ...