前言
运算符重载是面向对象程序设计中最令人兴奋的特性之一。它能将复杂而晦涩的程序边的更为直观。运算符重载增强了c++语言的可扩充性。一般来说,运算符重载允许一个大的运算符集,其目的是提供用自然方式扩充语言。
一、运算符重载的给规则
初步认识运算符
一般来说a+b=c;只对基本类型有效,对于表达式
a=3+4;
a=“abc”+“bcd”
都是正确的,在这里同一个运算符“+”,由于所操作的数据类型不同而具有不同的意义,这就是运算符重载,而且是系统预先定义的运算符重载。运算符重载就是赋予已有的运算符多重含义。
运算符重载的规则
(1).重载运算符必须符合语言语法;
eg:float f;
3.14=f;(错误)
(2).不能重载对内部c++数据类型进行操作的运算符
例如,不能重载二元浮点剑法运算符。
(3).不能创建新的运算符
(4).不能重载下面的运算符
.类成员选择符
.*成员指针运算符
::作用运算符
?:条件表达式运算符
除此之外的运算符都可以被重载,并且只有“=”的重载函数不能被继承;
(5)重载运算符要保持原有的基本语义不变。
编译程序选择重载运算符的规则
因为运算重载是一个函数,所以运算符的重载实际上是函数的重载。编译程序对运算符重载的选择,是遵循函数重载的选择原则。
运算符重载的形式
每个运算符的操作数都是语言规定好的,当金星运算符重载的时候,也必须遵循这个规定。当在类中重载操作符是,为使运算符函数能够访问类中声明的私有成员,那么运算符函数就必须被重载为非静态成员函数,或友元函数。
用成员函数重载运算符
格式:<返回类型>operator<运算符>(参数列表)
由于每个非静态成员函数都带有一个隐含的自引用参数this指针,对于一元运算符函数,不用显示声明形参。所需要的形参将由自引用参数提供。而对于二元运算符函数,只需显示声明右操作数,左操作数则由自引用参数提供。总之,用成员函数重载运算符需要的参数的个数总比它的操作数少一。
例:
#include<iostream> using namespace std; class Complex { public: Complex(double r = 0.0, double i = 0.0); Complex operator + (Complex c); //重载二元加; Complex operator - (Complex c); //重载二元减; void display(); private: double real, imag; //这个是复数类,python中有这个函数,后面更新python的时候会介绍; }; Complex::Complex(double r, double i) { real = r; imag = i; } //重载加法二元函数; Complex Complex::operator + (Complex c) { Complex temp; temp.real = real + c.real; temp.imag = imag + c.imag; return temp; } Complex Complex::operator - (Complex c) { Complex temp; temp.real = real - c.real; temp.imag = imag - c.imag; return temp; } void Complex::display() { const char *str; //前面必须加const,否则无法将X型赋给char*类型; str = (imag < 0) ? "" : "+"; cout << real << str << imag << "i" << endl; } int main() { Complex c1(12.4, 13.3), c2(14.4, 25.6); Complex c; cout << "c1="; c1.display(); cout << "c2="; c2.display(); c = c1 + c2; //c=c1.operator+(c2); cout << "c1+c2="; c.display(); c = c1 - c2; //c=c1.operator-(c2); cout << "c1-c2="; c.display(); return 0; }
用友元函数重载运算符
用友元函数重载运算符的原型为:
friend<返回值类型>operator<运算符>(形参);
其中标识符的含义与成员函数重载运算符的格式中的同名标识符的含义相同。由于友元函数不是类的成员,所以没有this指针,所以参数的个数都必须声明。
例:
#include<iostream> using namespace std; class Complex { public: Complex(double r = 0, double i = 0); friend Complex operator + (Complex c1, Complex c2); //重载二元加; friend Complex operator-(Complex c1, Complex c2); //重载二元减; void display(); private: double real, imag; }; Complex::Complex(double r, double i) { real = r; imag = i; } Complex operator+(Complex c1, Complex c2) { Complex temp; temp.imag = c1.imag + c2.imag; temp.real = c1.real + c2.real; return temp; } Complex operator-(Complex c1, Complex c2) { Complex temp; temp.real = c1.real - c2.real; temp.imag = c1.imag - c2.imag; return temp; } void Complex::display() { const char* str; str = (imag < 0) ? "" : "+"; cout << real << str << imag << "i" << endl; } int main() { Complex c1(12.4, 13.3), c2(14.4, 26.5); Complex c; cout << "c1="; c1.display(); cout << "c2="; c2.display(); c = c1 + c2; cout << "c1+c2="; c.display(); c = c1 - c2; cout << "c1-c2="; c.display(); return 0; }
两种运算符重载形式的比较
在许多情况下,用友元函数还是成员函数重载运算符在功能上没有什么区别,有时将二元运算符重载为友元函数比重载为成员函数使用起来灵活。例如:
c=34.4+c1;
如果使用“+”成员函数重载,会报错,因为该语句右边的表达式被解释为
34.5.operator+(c1);
当然,重载为友元函数也有一些限制。
第一:为保持与c++中规定的赋值语句语义一样,赋值运算符不能重载为友元函数,同理,“+=,-="等赋值运算符重载为成员运算符。
第二:友元函数不能重载”()[ ]和->"运算符。
第三:在重载增量或减量运算符时,若使用友元重载,则需要引用参数;
单目运算符重载
c++中有三种运算符,一种是单目运算符,双目运算符,还有就是三目运算符(条件运算符)。条件运算符不能被重载,前面介绍了双目运算符重载问题,现在我们介绍一下单目运算符的重载。
单目重载运算符和双目运算符重载有很多相似地方,主要就是参数个数不同,下面我们以“++”和“–”运算符作为例子来实现:
用成员函数形式重载运算符“++”和“–”:
以成员函数方式重载前缀“++”运算符的原型的一般格式:
《返回类型》::operator++()
以类成员方式重载后缀“++”运算符的原型的格式:
<返回类型>::operator++
其中给出了一个int参数表明调用该函数是运算符“++”应放在操作数的后面,且参数本身在函数体中并不被使用,因此没有给出参数名字。
#include<iostream> using namespace std; class Counter { public: Counter() { value = 0; } Counter(int i) { value = i; } Counter operator++(); //前缀++运算符 Counter operator++(int); //后缀++运算符 Counter operator--(); //后缀--运算符; Counter operator --(int); //后缀--运算符; inline void display() { cout << value << endl; } private: unsigned value; }; //前缀++运算符的重载; Counter Counter::operator++() { value++; return *this; } //后缀++运算符的重载; Counter Counter::operator++(int) { Counter temp; temp.value = value++; return temp; //value++; //return *this; } //前缀--运算符的重载; Counter Counter::operator--() { value--; return *this; } //后缀--运算符的重载; Counter Counter::operator--(int) { Counter temp; temp.value = value--; return temp; } int main() { Counter n(10), c; c = ++n; cout << "前缀++运算符的计算结果:" << endl; cout << "n= ", n.display(); cout << "c= ", c.display(); c = n++; cout << "后缀++运算符计算结果:" << endl; cout << "n= ", n.display(); cout << "n= ", c.display(); c = --n; cout << "前缀运算符--计算结果:" << endl; cout << "n= ", n.display(); cout << "c= ", c.display(); c = n--; cout << "后缀运算符的计算结果:" << endl; cout << "n= ", n.display(); cout << "c= ", c.display(); return 0; }
用友元函数形式重载运算符++,–:
友元函数实现单目运算符重载和双目运算符重载有异曲同工之处。只不过,由于友元函数没有this指针,而又不能改变++运算符的愿意,所以只能通过引用的方式,传参给指定的参数。
用友元函数重载前缀++运算符:
<类型>operator++(类名&);
用友元函数重载后缀++运算符:
<类型>operator++(类名&,int)
“–”运算符和++运算符重载方式相似,通过下面的程序来认识他们:
#include<iostream> using namespace std; class Counter { public: Counter() { value = 0; } Counter(int i) { value = i; } friend Counter operator++(Counter&); //++运算符前缀重载; friend Counter operator++(Counter&, int); //++运算符后缀重载; friend Counter operator--(Counter&); friend Counter operator--(Counter&, int); void display() { cout << value << endl; } private: unsigned value; }; Counter operator++(Counter& p) //最前面的counter是函数返回类型; { p.value++; return p; } Counter operator++(Counter& p, int) { Counter temp; temp = p.value++; return temp; } Counter operator--(Counter&p) { p.value--; return p; } Counter operator--(Counter& p, int) { Counter temp; temp.value = p.value--; return temp; } int main() { Counter n(10), c; c = ++n; cout << "前缀++运算符的计算结果:" << endl; cout << "n= ", n.display(); cout << "c= ", c.display(); c = n++; cout << "后缀++运算符计算结果:" << endl; cout << "n= ", n.display(); cout << "n= ", c.display(); c = --n; cout << "前缀运算符--计算结果:" << endl; cout << "n= ", n.display(); cout << "c= ", c.display(); c = n--; cout << "后缀运算符的计算结果:" << endl; cout << "n= ", n.display(); cout << "c= ", c.display(); return 0;