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. 第2章 变量和基本类型 附3---底层const和顶层const

    和英文版的对: As we’ve seen, a pointer is an object that can point to a different object. As a result,we c ...

  2. c语言编程之二叉排序树

    二叉排序树,又称为二叉查找树.它是一颗空树,或者是具有下面的性质的二叉树: 1.若它的左子树不空,则左子树上所有节点的值均小于它的根结构的值: 2.若它的右子树不空,则右子树上所有节点的值均大于它的根 ...

  3. Visual Studio 2013 各版本注册码

    Visual Studio Ultimate 2013 KEY(密钥):BWG7X-J98B3-W34RT-33B3R-JVYW9 Visual Studio Premium 2013 KEY(密钥) ...

  4. selenium--嵌套frame定位

    网页源码: 案例1 :iframe有id.name属性 网页上有3个frame:header.menu.main,分别代码顶部.左侧.右侧(其中menu.main在另外一个frameset中) 如何定 ...

  5. UVALive - 6572 Shopping Malls floyd

    题目链接: http://acm.hust.edu.cn/vjudge/problem/48416 Shopping Malls Time Limit: 3000MS 问题描述 We want to ...

  6. 以前用过Extjs技术的开发人员在学习Extjs4时需要注意的问题

            以前学习过Extjs的同学,在学习Extjs4的时候需要注意几个关键改变: 1.Extjs4的新的类系统. 2.Extjs4中MVC思路 3.Extjs4中的新的命名规范(结合新的MV ...

  7. 使用XmlInclude解决WebService调用时无法识别子类的异常

    一.定义抽象类及子类,WebMethod实际返回子类参数 //使用XmlInclude解决WebService调用时无法识别子类的异常 [System.Xml.Serialization.XmlInc ...

  8. WebServices中Xml的序列化

    一.定义序列化实体类 [System.Xml.Serialization.XmlRoot("Custome_Xml_Root_Name")] //自定义生成的Xml根目录名称 pu ...

  9. 【BZOJ】【1640】【USACO2007 Nov】/【1692】【USACO2007 Dec】队列变换

    后缀数组/贪心 每次从等待序列的头或尾拿出一个放到答案序列的末尾,那么每次贪心比较头和尾的字典序大小即可…… TAT贪心很好想,但是我一开始没想到是可以直接比较字符串大小……而是一位一位判的,WA了… ...

  10. Matlab实现movieLens转矩阵

    for mm=1:num_m %电影编号是mm的训练集行号 ff= find(train_vec(:,2)==mm); %train_vec(ff,1) 行号对应的用户编号 count(train_v ...