C++中运算符重载
概述:运算符重载是C++多态的重要实现手段之一。一般而言,对于双目运算符,最好将其重载为友元函数;而对于单目运算符,则最好重载为成员函数。但是一定要记得其中的例外情况。
运算符重载的四项基本原则:
a.不可臆造运算符。
b.运算符原有操作数的个数、优先级和结合性不能改变。
c.操作数中至少一个是自定义类型。
d.保持重载运算符的自然含义。
将运算符重载为成员函数还是友元函数呢?先来看看两者的区别:
a.当重载为成员函数时,会隐含一个this指针;当重载为友元函数时,将不存在隐含的this指针,需要在参数列表中显示地添加操作数。
b.当重载为成员函数时,只允许右参数的隐式转换;当重载为友元函数时,能够接受左参数和右参数的隐式转换。如下代码:
class CString
{
public:
private:
};
因为CString的构造函数参数为一个char*,所以如果采用友元形式的operator +(const CString&, const CString&),那么char+CString和CString+char都能正常工作;而如果采用的是成员函数形式的CString::operator +(const CString& rhs),则只能接受CString+char,如果执行char+CString则会编译出错。
需要注意的是,隐式转换由于临时变量的增加往往效率不高。如果应用程序对效率要求较高,针对以上类,建议选择定义多个运算符的友元重载版本:
CString& operator +(const CString&, const CString&);
CString& operator +(const char*, const CString&);
CString& operator +(const CString&, const char*);
一般来说,建议遵守这么一个不成文的规定:
对于双目运算符,最好将其重载为友元函数,因为这样更方便些;对于单目运算符,则最好重载为成员函数。
当然也有例外的情况,有些双目运算符是不能重载为友元函数的,比如赋值运算符=、函数调用运算符()、下表运算符[]、指针->等,因为这些运算符在语义上与this都有太多的关联。
还有一个需要特别说明的就是输出运算符<<。因为<<的第一个操作数一定是ostream类型,所以<<只能重载为友元函数,如下:
friend ostream& operator <<(ostream& os, const Complex& c);
ostream& operator <<(ostream& os, const Complex& c)
{
}
1、运算符重载是为了对用户自定义数据类型的数据的操作与内定义的数据类型的数据的操作形式一致。不能重载的5个运算符:*成员指针访问运算符;::域运算符;sizeof长度运算符;?:条件运算符;.成员访问符。
运算重载的三种方式:普通函数,友元函数,类成员函数。
当重载为成员函数时,双目运算符仅有一个参数。对单目运算符,重载为成员函数时,不能再显式说明参数。重载为成员函数时,总时隐含了一个参数,该参数是this指针。this指针是指向调用该成员函数对象的指针。
运算符重载函数还可以为友元函数。当重载友元函数时,将没有隐含的参数this指针。这样,对双目运算符,友元函数有2个参数,对单目运算符,友元函数有一个参数。但是,有些运行符不能重载为友元函数,它们是:=,(),[]和->。
原因:有人说是因为
C++规定赋值运算符“=”只能重载为类的非静态成员函数,而不可以重载为类的友元函数。
不能重载为类的静态成员应该比较容易理解,因为静态成员函数是属于整个类的,不是属于某个对象的,它只能去操作类静态数据成员。而赋值运算符“=”是基于对象操作的。
当把赋值运算符重载为类的友员函数,在程序中执行类对象的赋值语句时,程序就会出现两种矛盾的选择。
(1)因为它认为类中并没有重载赋值运算符的成员函数,所以它根据C++的规则,会去调用相应的构造函数。
(2)但是在全局里,我们已经重载了参数类型为此类类型的赋值运算符函数,而这赋值语句刚好和这函数匹配上了,根据C++的规则,也会去调用这函数。
程序是不允许有矛盾不确定选择的,所以当赋值运算符重载为类的友元函数时,编译器就会提示错误。
2、流运算符为什么不能重载为成员函数,只能用友元函数重载,cout<<obj;
cout << f1 << f2;
//用重载运算符表示,只能通过友员来实现,如果要用成员函数,则会有cout.operator<<(const F& f),所以这是不可能的.因此只能用友员来实现,operator<<(cout,f) 而cout是ostream型的,因此有以下标准格式.注意不能加const,因为cout是要改变的,会改变里的缓冲成员.
friend ostream& operator<<( ostream& cout, constF&) //输出运算符的标准重载格式.
friend istream& operator>>(istream& is, F& f){ } //输入运算符重载标准格式
#include <iostream>
using namespace std;
class F{
int n;
int d;
public :
F(int n=0, int d=1):n(n),d(d){}
friend ostream& operator<<(ostream& os, const F& f){
os << '[' << f.n << '/' << f.d <<']';
return os;
}
F operator*(const F& o) {
return F(n*o.n,d*o.d);
}
friend F operator/(const F& f1,const F& f2){
return F(f1.n/f2.d,f1.d/f2.n);
}
friend istream& operator>>(istream& is, F& f){
char ch;
is >> f.n >> ch >> f.d;
return is;
}
};
int main()
{
F f1(3,5),f2(11,7),f;
cout << f1 << '*' << f2 << '=' << f1*f2 << endl;
cout << f1 << '/' << f2 << '=' << f1/f2 << endl;
cout << "Input 2 fractions :";
cin >> f1 >> f2;
cout <<"f1=" << f1 << endl;
cout << "f2=" << f2 << endl;
}
3、在类成员函数中重载运算符是不允许返回引用的,会出现“返回局部变量的地址”警告
4、把后++,后--当作双目运算符,第二个操作数是整形
单目运算符重载
-友元函数形式:返回类型 operatorX(形参)
使用:X obj ---> operatorX(obj);
-成员函数形式 尽量用成员:返回类型 operatorX(/*无形参*/)
使用: X obj ---> obj.operator();
#include <iostream>
using namespace std;
class A{
int data;
public :
A(int d=0):data(d){}
friend ostream& operator<<(ostream& os,const A& a){
os << a.data;
return os;
}
friend istream& operator>>(istream& is,A& a){
is >> a.data;
return is;
}
friend A& operator++(A& a){
a.data += 10;
return a;
}
A& operator--(){
data -= 10;
return *this;
}
friend A/* 不能用引用 */ operator++(A& a,int){
A old(a);
a.data += 1;
return old;
}
A /* 不能用引用 */ operator--(int){
A old(*this);
data -= 1;
return old;
}
};
int main()
{
A a1(50),a2(100);
cout << "a1=" <<a1 << endl;
cout << "a2=" <<a2 << endl;
cout << "++a1=" << ++a1 << endl;
cout << "--a1=" << --a1 << endl;
cout << "a1++=" << a1++ << endl;
cout << "a1=" <<a1 << endl;
cout << "a2--=" << a2-- << endl;
cout << "a2=" <<a2 << endl;
}
5、强制类型转换:类型(数据) --> (不必写返回类型,因为始终与后面的类 型是相同的) operator类型(无形参) 只能写成成员函数,不能是友员.
#include<iostream>
using namespacestd;
classA{
intdata;
public:
A(intd=0):data(d){}
operator int(){
returndata;
}
operator bool(){
returndata!=0;
}
operator char(){
return(char)data;
}
};
intmain()
{
A a1(65),a2(200);
cout << "a1="<< (char)a1 << endl;
intd=a2;
if(a2)
cout << "good"<< endl;
}