运算符重载.docx
《运算符重载.docx》由会员分享,可在线阅读,更多相关《运算符重载.docx(24页珍藏版)》请在冰豆网上搜索。
运算符重载
运算符重载
18.1运算符重载的需要性
1.所谓运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。
例18.1
classA
{
public:
A(intx){a=x;}
protected:
inta;
};
Aa(5),b(10),c;
c=a+b;//错误,因+运算符不适合类对象,但我们可重载该运算符,使其适应类对象。
18.2如何重载运算符
1.运算符重载是通过运算符重载函数完成的。
运算符重载函数可以是类的成员函数,也可以是类的友元函数。
2.运算符重载函数定义格式。
(1)单目运算符重载函数定义
类型operator单目运算符(参数)函数体
函数名
(2)双目运算符重载函数定义
类型operator双目运算符(参数1,参数2)函数体
函数名
(3)单目运算符重载函数调用
operator单目运算符(实参)单目运算符实参
(3)单目运算符重载函数调用
operator双目运算符(实参1,实参2)实参1双目运算符实参2
3.因成员函数有一个默认的参数this,故运算符重载函数是类的成员函数时,其参数可比格式中的参数少一个。
例18.2用友元函数对二维向量重载双目运算符+和单目运算符++。
#include
classvector
{
intx,y;
public:
vector();
vector(intx1,inty1);
voidprint();
friendvectoroperator++(vector&v1,int);//单目运算符++重载函数原型
friendvectoroperator+(vector&v1,vector&v2);//双目运算符+重载函数原型
};
vector:
:
vector(){x=0;y=0;}
vector:
:
vector(intx1,inty1){x=x1;y=y1;}
voidvector:
:
print(){cout<<"\n("<vectoroperator++(vector&v1,int)
{
vectorv2(v1.x,v1.y);
v1.x++;
v1.y++;
returnv2;
}
vectoroperator+(vector&v1,vector&v2)
{
vectorv0;
v0.x=v1.x+v2.x;
v0.y=v1.y+v2.y;
returnv0;
}
main()
{
vectorv1(10,10);
v1.print();
vectorv11;
v11=v1++;//即v11=operator++(v1,1);
v1.print();
v11.print();
vectorv2(20,20);
(v1+v2).print();//即operator+(v1,v2).print();
vectorv3;
v3=v1+v2;//即v3=operator+(v1,v2);
v3.print();
v3++.print();//即operator++(v3,1).print();
return0;
}
运行结果:
(10,10)
(11,11)
(10,10)
(31,31)
(31,31)
(31,31)
例18.3用成员函数对二维向量重载双目运算符+和单目运算符++。
#include
classvector
{
intx,y;
public:
vector();
vector(intx1,inty1);
voidprint();
vectoroperator++(int);//单目运算符++重载函数原型
vectoroperator+(vectorv);//双目运算符+重载函数原型
};
vector:
:
vector(){x=0;y=0;}
vector:
:
vector(intx1,inty1){x=x1;y=y1;}
voidvector:
:
print(){cout<<"\n("<vectorvector:
:
operator++(int)
{
vectorv2(x,y);
x++;
y++;
returnv2;
}
vectorvector:
:
operator+(vectorv)
{
vectorv0;
v0.x=x+v.x;//x即this->x
v0.y=y+v.y;//y即this->y
returnv0;
}
main()
{
vectorv1(10,10);
v1.print();
vectorv11;
v11=v1++;//即v11=v1.operator++
(1);
v1.print();
v11.print();
vectorv2(20,20);
(v1+v2).print();//即v1.operator+(v2).print();
vectorv3;
v3=v1+v2;//即v3=v1.operator+(v2);
v3.print();
v3++.print();//即v3.operator++
(1).print();
return0;
}
运行结果:
(10,10)
(11,11)
(10,10)
(31,31)
(31,31)
(31,31)
例18.4对RMB(人民币)类重载运算符+和*。
#include
classRMB//定义RMB类
{
public:
RMB(doubled){yuan=d;jf=(d-yuan)/100;}//构造函数
RMBinterest(doublerate);//计算利息成员函数原型
RMBadd(RMBd);//计算人民币相加成员函数原型
voiddisplay()//显示人民币成员函数定义
{
cout<<(yuan+jf/100.0)<}
RMBoperator+(RMBd)//双目运算符+重载函数定义
{
returnRMB(yuan+d.yuan+(jf+d.jf)/100);
}
RMBoperator(doublerate)//双目运算符*重载函数定义
{
returnRMB((yuan+jf/100)*rate);
}
private:
unsignedintyuan;//元
unsignedintjf;//角分
};
RMBRMB:
:
interest(doublerate)//计算利息成员函数定义
{
returnRMB((yuan+jf/100.0)*rate);
}
RMBRMB:
:
add(RMBd)//计算人民币相加成员函数定义
{
returnRMB(yuan+d.yuan+jf/100.0+d.jf/100.0);
}
RMBexpense1(RMBprinciple,doublerate)//principle表本金,rate表利率
{
RMBinterest=principle.interest(rate);
returnprinciple.add(interest);
}
RMBexpense2(RMBprinciple,doublerate)//principle表本金,rate表利率
{
RMBinterest=principle*rate;//双目运算符*重载函数调用
returnprinciple+interest;//双目运算符+重载函数调用
}
voidmain()
{
RMBx=10000.0;
doubleyrate=0.035;
expense1(x,yrate).display();
expense2(x,yrate).display();
}
其中RMBinterest=principle*rate;RMBinterest=operator*(principle,rate);
returnprinciple+interest;returnoperator+(principle,interest);
例18.5对RMB(人民币)类重载运算符+和++。
#include
classRMB//定义RMB类
{
public:
RMB(unsignedintd,unsignedintc);//构造函数原型
friendRMBoperator+(RMB&,RMB&);//双目运算符+重载函数原型
friendRMB&operator++(RMB&);//单目运算符++重载函数原型
voiddisplay()//显示人民币成员函数定义
{
cout<<(yuan+jf/100.0)<}
protected:
unsignedintyuan;//元
unsignedintjf;//角分
};
RMB:
:
RMB(unsignedintd,unsignedintc)//构造函数定义
{
yuan=d;
jf=c;
while(jf>=100)
{
yuan++;
jf-=100;
}
}
RMBoperator+(RMB&s1,RMB&s2)
{
unsignedintjf=s1.jf+s2.jf;
unsignedintyuan=s1.yuan+s2.yuan;
RMBresult(yuan,jf);
returnresult;
}
RMB&operator++(RMB&s)
{
s.jf++;
if(s.jf>=100)
{
s.jf-=100;
s.yuan++;
}
returns;
}
voidmain()
{
RMBd1(1,60);
RMBd2(2,50);
RMBd3(0,0);
d3=d1+d2;
++d3;
d3.display();
}
运行结果:
4.11
18.3值返回和引用返回
1.上例中,为何RMBoperator+()由值返回,而RMB&operator++()由引用返回?
结论:
若函数返回的结果不为左值,则可由值返回;若函数返回的结果要求为左值,则应由引用返回。
2.若operator++()不以引用返回,而以值返回,即
RMBoperator++(RMB&s)
{
s.jf++;
if(s.jf>=100)
{
s.jf-=100;
s.yuan++;
}
returns;
}
voidmain()
{
RMBa(2,50);
c=a++;//ok
c=++a;//ok,a为2.52
c=++(++a);//error,a为2.53,理应为2.54
}
18.4运算符重载函数作为成员函数
1.运算符重载函数作为成员函数
例18.6对RMB(人民币)类重载运算符+和++,要求运算符重载函数作为成员函数。
#include
classRMB//定义RMB类
{
public:
RMB(unsignedintd,unsignedintc);//构造函数原型
RMBoperator+(RMB&);//双目运算符+重载函数原型
RMB&operator++();//单目运算符++重载函数原型
voiddisplay()//显示人民币成员函数定义
{
cout<<(yuan+jf/100.0)<}
protected:
unsignedintyuan;//元
unsignedintjf;//角分
};
RMB:
:
RMB(unsignedintd,unsignedintc)//构造函数定义
{
yuan=d;
jf=c;
while(jf>=100)
{
yuan++;
jf-=100;
}
}
RMBRMB:
:
operator+(RMB&s)
{
unsignedintc=jf+s.jf;
unsignedintd=yuan+s.yuan;
RMBresult(d,c);
returnresult;
}
RMB&RMB:
:
operator++()
{
jf++;
if(jf>=100)
{
jf-=100;
yuan++;
}
return*this;
}
voidmain()
{
RMBd1(1,60);
RMBd2(2,50);
RMBd3(0,0);
d3=d1+d2;//d3=d1.operator+(d2);
++d3;//d3.operator++();
d3.display();
}
运行结果:
4.11
注:
作为成员运算符重载函数比作为非成员的运算符重载函数,声明和定义上,形式上少了一个参数。
这是由于c++对所有的成员函数隐藏了第一个参数this。
18.5重载增量运算符
1.前增量和后增量的区别
前增量(++a):
先对对象进行增量修改,再返回该对象。
返回结果为左值。
后增量(a++):
创建临时对象保存原对象,再返回临时对象。
后对原对象进行增量修改,返回结果为非左值。
2.成员形式的重载
(1)c++规定:
重载后增量运算符时,加上一个无实际意义的整数形参。
(2)重载前增量运算符时返回引用,重载后增量运算符时返回值。
例18.7用成员形式重载前增量运算符和后增量运算符。
#include
classincrease
{
public:
increase(intx):
value(x){}
increase&operator++();//前增量操作符重载函数原型
increaseoperator++(int);//后增量操作符重载函数原型
voiddisplay()
{
cout<<"thevalueis"<}
private:
intvalue;
};
increase&increase:
:
operator++()
{
value++;//先增量
return*this;//再返回原对象
}
increaseincrease:
:
operator++(int)
{
increasetemp(*this);//临时对象存放原有对象值
value++;//原有对象增量修改
returntemp;//返回原有对象值
}
voidmain()
{
increasen(20);
n.display();
(n++).display();
n.display();
++n;
n.display();
++(++n);
n.display();
(n++)++;//第二次增量操作对临时对象进行
n.display();
}
运行结果:
thevalueis20
thevalueis20
thevalueis21
thevalueis22
thevalueis24
thevalueis25
3.非成员形式的重载
例18.8用非成员形式重载前增量运算符和后增量运算符。
#include
classincrease
{
public:
increase(intx):
value(x){}
friendincrease&operator++(increase&);//前增量操作符重载函数原型
friendincreaseoperator++(increase&,int);//后增量操作符重载函数原型
voiddisplay()
{
cout<<"thevalueis"<}
private:
intvalue;
};
increase&operator++(increase&a)
{
a.value++;
returna;
}
increaseoperator++(increase&a,int)
{
increasetemp(a);
a.value++;
returntemp;
}
voidmain()
{
increasen(20);
n.display();
(n++).display();//显示临时对象
n.display();//显示原有对象
++n;
n.display();
++(++n);
n.display();
(n++)++;//第二次增量操作对临时对象进行
n.display();
}
运行结果:
thevalueis20
thevalueis20
thevalueis21
thevalueis22
thevalueis24
thevalueis25
18.6转换运算符
1.转换运算符声明:
operator类型名();
(1)无返回类型。
(2)将对象转换成类型名规定的类型。
例18.9将RMB类对象转换成double型。
#include
classRMB//定义RMB类
{
public:
RMB(doublevalue=0.0);//构造函数原型
operatordouble()//转换运算符
{
returnyuan+jf/100.0;
}
voiddisplay()//显示人民币成员函数定义
{
cout<<(yuan+jf/100.0)<}
protected:
unsignedintyuan;//元
unsignedintjf;//角分
};
RMB:
:
RMB(doublevalue)//构造函数定义
{
yuan=value;
jf=(value-yuan)*100+0.5;
}
voidmain()
{
RMBd1(2.0),d2(1.5),d3;
d3=RMB((double)d1+(double)d2);//显示转换
d3=d1+d2;//隐式转换
d3.display();
}
结果:
3.5
其中d3=d1+d2执行过程:
(1)寻找成员函数的+运算符(无)
(2)寻找非成员函数的+运算符(无)
(3)假定匹配operator+(double,double)
(4)寻找转换运算符operatordouble()(有)。
故将d1和d2转换成double型,再相加,结果为double型,而d3为RMB型,故再将右边的double型表达式转换成RMB型临时对象,赋值给RMB对象d3。
2.转换运算符和转换构造函数互逆。
如:
RMB:
:
operatordouble();//转换运算符,将RMB型转换成double型
RMB:
:
RMB(double);//转换构造函数,将double型转换成RMB型
18.7赋值运算符重载
1.赋值运算符
(1)
(1) structs{inta,b;};
sx,y;
x=y;//ok
(2)inta[5];
intb[]={3,4,5,6};
a=b;//error,因数组名是指针常量
(3)voidfn(myclass&mc)
{
myclassnewmc=mc;//调用拷贝构造函数进行初始化
newmc=mc;//赋值运算符
}
(4)拷贝构造函数用已存在的对象创建一个相同的新对象。
而赋值运算符把一个对象的成员变量值赋予一个已存在的同类对象的同名变量。
(5)如果在类中没有说明本身的拷贝构造函数和赋值运算符,编译程序将会提供,但它们都只是对对象进行成员浅拷贝。
在那些以指向堆空间指针作为数据成员的类中,必须避免使用浅拷贝,而要为类定义自己的赋值运算符,以给对象分配堆内存。
2.如何重载赋值运算符
例18.10赋值运算符重载
#include
#include
className
{
public:
Name(){pname=0;}//默认构造函数
Name(char*pn){copyname(pn);}//构造函数
Name(Name&s){copyname(s.pname);}//拷贝构造函数
~Name()//析构函数
{
deletename();
}
Name&operator=(Name&s)//赋值运算符重载函数
{
deletename();
copyname(s.pname);
return*this;
}
voiddisplay()
{cout<protected:
voidcopyname(char*pn);
voiddeletename();
char*pname;
};
voidName:
:
copyname(char*pn)
{
pname=newchar[strlen(pn)+1];
if(pname)
{
strcpy(pname,pn);
}
}
voidName:
:
deletename()
{
if(pname)
{
deletepname;
pname=0;
}
}
voidmain()
{
Names("claudette");
Namet("temporary");
t.display();
t=s;//赋值
t.display();
}
结果:
temporary
claudette
关闭窗口