运算符重载就是用同一个运算符完成不同的运算功能,和函数重载一样,运算符重载是在编译阶段完成的,体现出静态的多态性。
C++运算符重载的规定如下:
- 不能改变原运算符的优先级
- 不能改变原运算符的结合性
- 默认参数不能和运算符重载一起使用
- 不能改变原运算符的操作数个数
- 不能创建新的运算符,且部分已有运算符可能因为存在二义性问题所以无法被重载
- 当运算符作用于C++内部提供的数据类型时,原来的含义保持不变。
- 运算符可以被重载用于用户定义的类对象或者用户定义的类对象与内置数据类型变量的组合
C++中不能重载的运算符:
- .
- .*
- ::
- ?:
- sizeof
运算符重载为类成员函数时主要有3种形式:重载为类的成员函数、重载为类的友元函数、重载为普通函数。
重载++,–单目运算符
++和–重载运算符有前缀和后缀两种运算符重载形式,这里以++重载运算符为例,采用成员函数重载。
#include<iostream> using namespace std; class A { int n; public: A(int i){n = i;} operator ++(){//重载前缀运算符 n++; } operator ++(int){//重载后缀运算符 n = n+2; } void show(){ cout<<"n="<<n<<endl; } }; int main() { A a(5); A b(5); ++a; b++; a.show(); b.show(); }
输出结果为:
n=6 n=7
如果改用成员函数的调用方式,重载后缀运算符的调用方式是a.operator++(1),其中1可以改为任意整数,它只是一个占位符。重载前缀运算符的调用方式是b.operator()。
重载下标运算符
下标运算符[]通常用于取数组的某个元素,下标运算符重载可以实现数组下标的越界检测等,如下Words类所示:
class Words { int len; char *str; public: Words(char *s){ str = new char[strlen(s)+1]; strcpy(str,s); len = strlen(s); } char operator[](int n){ if(n > len-1){ cout<<"数组下标越界"; return ' ';//返回一个特殊字符即可 } else return *(str+n); } };
重载运算符new/delete
C++提供了new和delete两个运算符用于内存管理,在大多数情况下它们是非常有效的,但在有些情况下需要自己管理内存,以克服原new与delete的不足,这就是重载运算符new和delete。delete和delete只能被重载为类的成员函数或者普通函数,不能被重载为友元函数,而且不论是否使用关键字static进行修饰,重载了的new和delete均为类的静态成员函数。
重载new运算符的一般格式:
void *类名::operator new(size_t size,其他形参){ //使用malloc完成分配工作 //完成自己需要的操作 return void *型指针; }
上述new重载函数应返回一个无值型的指针,形参可以有多个,但第1个参数一定是size_t类型的参数,它表示要分配空间的大小,再调用时由系统自动获取。
在使用重载new运算符时先调用new的重载成员函数,再调用该类的构造函数。
重载delete运算符的一般格式:
void *类名::operator delete(void *p){ //使用free完成内存释放工作 //完成自己需要的操作 }
在使用重载delete运算符时默认先调用类的析构函数,再调用重载的delete成员函数。
重载new[]/delete[]和重载new/delete类似。
重载输入/输出运算符
重载插入运算符的一般格式如下:
friend ostream& operator<< (ostream & stream,类名 &类引用名){ //函数体 return stream; }
重载输出运算符的一般格式如下:
friend istream& operator>> (ostream & stream,类名 &类引用名){ //函数体 return stream; }