第12章C语言Word格式文档下载.docx
《第12章C语言Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《第12章C语言Word格式文档下载.docx(18页珍藏版)》请在冰豆网上搜索。
//分母
};
fractionnum1,num2,num3;
num3=num1+num2;
//试图执行两个分数的加法运算,编译错误errorC2676:
num1=num3-num2;
//试图执行两个分数的减法运算,编译错误errorC2676:
编译时提示errorC2676:
binary'
+'
:
'
structmain:
:
fraction'
doesnotdefinethisoperatororacon-
versiontoatypeacceptabletothepredefinedoperator错误。
显然,编译系统不知道对num1,
num2,num3变量应进行怎样的“+”和“-”操作?
若要实现结构体变量的加法或减法运算,可采用以下两种方法,一种是按照一般函数的定义规则分别定义一个用于完成加法功能的函数和一个用于完成减法功能的函数。
另一种是按照运算符重载函数的定义规则分别对现有运算符“+”和“-”进行重载。
例12.1-1用函数方法(方法一)来实现结构体变量的加法
#include<
iostream.h>
fractionAdd(constfraction&
num1,constfraction&
num2)//定义函数
{fractiontemp_num;
//定义临时工作变量
intn,m,k;
n=num1.numerator*num2.denominator;
m=num2.numerator*num1.denominator;
temp_num.numerator=n+m;
//计算分子
temp_num.denominator=num1.denominator*num2.denominator;
//计算分母
n=temp_num.numerator;
m=temp_num.denominator;
/*将计算结果化简为最简分数*/
k=m%n;
while(k)
{m=n;
n=k;
k=m%n;
}
temp_num.numerator/=n;
temp_num.denominator/=n;
/*化简完毕*/
returntemp_num;
}
voidmain()
{fractionnum1,num2,num3;
cin>
num1.numerator>
num1.denominator;
//输入第一个分数的分子和分母
num2.numerator>
num2.denominator;
//输入第二个分数的分子和分母
num3=Add(num1,num2);
//将两个分数相加
cout<
num3.numerator<
"
/"
num3.denominator<
endl;
运行结果:
23↙
45↙
22/15
程序说明
♣运行时,从键盘输入23↙表示2/3,45↙表示4/5。
♣对Add()函数的参数,使用常引用的方法,其目的是为防止在函数中改变该参数的值,以保证被引用的实参不会发生变化。
运算符重载的定义格式
运算符重载分为单目运算符的重载和双目运算符的重载。
它是由关键字operator后跟一个运算符来实现的。
一般格式为
单目运算符的重载格式
返回值类型operator单目运算符(一个用户类型的参数声明){}
双目运算符的重载格式
返回值类型operator双目运算符(第一个参数声明,第二个参数声明){}
格式说明
♣运算符的重载格式有些象函数的形式。
即可以把operator运算符看作是一个函数名。
因此,运算符重载又称作运算符重载函数。
operator和后面的运算符之间有无空格均可。
♣运算符重载必须带有参数,并且至少要有一个用户自定义类型的参数。
♣对于单目运算符的重载来说,其参数表中只有一个用户自定义类型的参数。
♣对于双目运算符的重载来说,其参数表中第一个参数为双目运算符左边的对象,第二个参数为双目运算符右边的对象。
且二者中必须有一个是用户自定义类型。
♣对于单目运算符的后增1或后减1运算符,在重载时参数表中要增加一个整型参数,以便与前增1前减1区别,该整型参数是虚设的,可以只列出类型。
如fractionoperator++(fraction&
num,int);
例12.1-2重载运算符“+”(方法二)实现结构体变量的加法
structfraction
fractionoperator+(constfraction&
num2)//重载运算符“+”
{…//同前例略
…}
num3=num1+num2;
//可以使用重载的“+”运算符将两个分数相加
由此,我们实现了使用“+”运算符对自定义数据类型变量的加法运算。
它同函数实现的方法是一样的,但所表达的语义不同。
可以看出,使用重载的运算符后,比函数调用更简单,更能说明程序的意图。
该结构的减法运算请读者自己设计完成。
注意
♣C++中的运算符除了成员运算符“.”、条件运算符“?
”和作用域运算符“:
”以外,其它全部可以重载,而且只能重载已有的运算符。
♣重载之后运算符的优先级、操作对象个数和结合性都不会改变。
♣运算符重载是针对新类型数据的实际需要,对原有运算符所能处理的数据类型范围进行扩大,使之能够对新的数据类型执行功能相同的运算。
一般来讲,重载的功能应当与原有功能相类似,同时至少要有一个操作对象是用户自定义类型。
运算符重载实际上就是函数重载。
对于运算符将其视为一个函数,只不过形式有点特殊。
如,程序中遇有11+12的表达时,C++编译器将此表达式当作一次函数调用,即
intoperator+(11,12)
该函数给出2个整型数的加法操作,并返回一个整数;
而对于程序中遇有11.1+12.2时,C++编译器也将此表达式当作一次函数调用,即
intoperator+(11.1,12.2)
该函数给出2个实型数的加法操作,并返回一个实型数。
以上2个函数很相似,不同之处是:
第1个函数原型为intoperator+(inta,intb);
第2个函数原型为intoperator+(floata,floatb)。
如果将“operator+”理解为一个函数名,则与一般函数没有什么区别。
运算符重载一般采用2种形式,一种为成员函数形式,另一种为友元函数形式。
12.2运算符重载为类的成员函数形式
将运算符重载为类的成员函数,一般格式为
类型operator运算符(形参表)
{
函数体;
其中类型是指重载运算符的返回值类型;
operator是定义运算符重载的关键字;
运算符是指要重载的运算符名称。
形参表:
在表中列出了重载运算符所需要的参数和参数类型。
表中参数个数与重载运算符操作数的个数有关,即运算符重载函数的参数比原来的操作数少一个(后置++、--除外)。
具体地说,单目运算符参数表无参数,双目运算符参数表中只有一个参数。
也就是说,调用该参数的对象为第1个操作数,参数表中的参数为第2个操作数。
例12.2-1运算符重载:
复数四则运算与求负
分析:
复数c1=a+bi,c2=x+yi。
其中a,b,x,y均为实数;
c=c1+c2=(a+x)+(b+y)i
c=c1-c2=(a-x)+(b-y)i
c=c1*c2=(a+bi)*(x+yi)=(ax-by)+(bx+ay)i
c=c1/c2=(a+bi)/(x+yi)=((ax+by)/(x2+y2))+((bx-ay)/(x2+y2))i
c=-c1=-a-bi
c=-c2=-x-yi
//complex.h文件
classcomplex//定义复数类
{public:
complex(floatr=0.0,floati=0.0)//构造函数
{real=r;
imag=i;
complexoperator+(complex&
c);
//运算符“+”重载成员函数
complexoperator-(complex&
//运算符“-”重载成员函数
complexoperator*(complex&
//运算符“*”重载成员函数
complexoperator/(complex&
//运算符“/”重载成员函数
complexoperator-(void);
//运算符“求负”重载成员函数
voidshow();
//显示输出复数
private:
floatreal,imag;
//复数实部real,复数虚部imag
//complex.cpp文件
#include“complex.h”
complexcomplex:
operator+(complex&
c)//重载运算符“+”函数实现
{complexp;
p.real=real+c.real;
p.imag=imag+c.imag;
returnp;
operator-(complex&
c)//重载运算符“-”函数实现
p.real=real-c.real;
p.imag=imag-c.imag;
operator*(complex&
c)//重载运算符“*”函数实现
p.real=real*c.real-imag*c.imag;
p.imag=real*c.imag+imag*c.real;
operator/(complex&
c)//重载运算符“/”函数实现
p.real=(real*c.real+imag*c.imag)/(c.real*c.real+c.imag*c.imag);
p.imag=(imag*c.real-real*c.imag)/(c.real*c.real+c.imag*c.imag);
operator-(void)//重载“求负”操作函数实现
p.real=-real;
p.imag=-imag;
voidcomplex:
show()
{if(imag<
0)cout<
real<
”+”<
”(”<
imag<
”)”<
”i”<
elsecout<
//Ex12_2_1.cpp文件
{complexa(6,8);
//定义复数类的对象a
”a=”;
a.show();
complexb(2,4);
//定义复数类的对象b
”b=”;
b.show();
complexc1;
//定义复数类的对象c1
c1=a+b;
//使用重载运算符完成复数加法
”a+b=”;
c1.show();
c1=a-b;
//使用重载运算符完成复数减法
”a-b=”;
c1=a*b;
//使用重载运算符完成复数乘法
”a*b=”;
c1=a/b;
//使用重载运算符完成复数除法
”a/b=”;
c1=-a;
//使用重载运算符完成复数“求负”
”-a=”;
c1=-b;
”-b=”;
a=6+8i
b=2+4i
a+b=8+12i
a*b=-20+40i
a/b=2.2+(-0.4)i
-a=-6+(-8)i
-b=-2+(-4)i
♣把复数的四则运算(+、-、*、/)和“求负”重载为复数类的成员函数。
只在函数说明和实现时用了关键字operator。
在运算过程中,成员函数形式的运算符重载函数与类的一般成员函数完全相似,可以直接通过运算符、操作数来实现函数的调用。
运算符+、-、*、/和“求负”的功能没有变,对整型和实型等基本类型数据的运算仍遵循C++的基本语法规则,但是增加了对复数运算的功能。
♣程序中出现的为双目运算符,一般情况为:
a运算符b。
如
a+b,编译器将解释为
a.operator运算符(b),即
a.operator+(b)。
其中a和b为类的对象。
若运算符“+”被重载为复数运算的加法运算符,其中a为第1个操作数,b为第2个操作数,则它们都是complex的对象。
对于单目运算符,一般情况为:
a运算符或运算符a。
编译器将解释为
a.operator运算符()
♣本程序有3个文件构成:
头文件complex.h,扩展名为.h,类的成员函数形式的运算符重载在头文件中进行说明;
与头文件同名的源文件complex.cpp,扩展名为.cpp,类的成员函数形式的运算符重载函数在这个文件中定义(实现);
文件Ex12_2_1.cpp,扩展名为.cpp,是主函数文件。
将3个文件组合在一个项目中,这个程序才能运行,并得到结果。
例12.2-2运算符重载:
单目运算符++进行复数运算
//complex1.h文件
classcomplex//定义类complex
//公有成员函数,外部接口
complex(floata=0.0,floatb=0.0)//构造函数
{real=a;
imag=b;
voidoperator++();
//前置单目运算符重载
voidoperator++(int);
//后置单目运算符重载
//私有数据成员
//complex1.cpp文件
#include“complex1.h”
operator++()//前置单目运算符重载函数实现
{real++;
imag++;
operator++(int)//后置单目运算符重载函数实现
//定义复数类的对象
returncomplex(p.real,p.imag);
{cout<
if(imag<
//Ex12_2_2.cpp文件
{complexa(-1,8);
complexb(2,-11);
complexc;
//定义复数类的对象c
”firstoutput(a,b):
”<
1
c=a+b;
c.show();
++a;
++b;
”secondoutput(++a,++b):
a++;
b++;
”thirdoutput(a++,b++):
c.show();
firstoutput(a,b):
a+b=1+(-3)i
secondoutput(++a,++b):
a+b=3+(-1)i
thirdoutput(a++,b++):
a+b=5+1i
♣本程序由头文件complex1.h、同名的源文件complex1.cpp、和源文件Ex12_2_2.cpp这3个文件组合在一个项目中。
♣程序中把复数实部和虚部自增的前置++和后置++运算符重载为复数类的成员函数。
前置++和后置++单目运算符的重载的主要区别就是函数的形参:
前置++单目运算符重载函数无形参,后置++单目运算符重载函数有一个整数形参。
这个整数形参只是用于区分前置和后置,因此参数表中无参数名,只是给出了类型名。
例12.2-3赋值运算符“=”,“+=”,“-=”重载
#include<
classpoint
point(){}
point(intaa,intbb)
{a=aa;
b=bb;
voidshow()
{cout<
a<
”,”<
b<
pointoperator=(point&
);
pointoperator+=(point&
voidoperator-=(pointc)
{a-=c.a;
b-=c.b;
inta,b;
pointpoint:
operator=(point&
c)
{a=c.a;
b=c.b;
return*this;
operator+=(point&
{a+=c.a;
b+=c.b;
{points(4,5),r(6,8),t;
t=s;
”t=”;
t.show();
”s:
”;
s.show();
”r:
r.show();
s+=r;
”s+=r:
s-=r;
”s-=r:
t=(4,5)
s:
(4,5)
r:
(6,8)
s+=r:
(10,13)
s-=r:
♣赋值运算符“=”是双目运算符,赋值运算符的重载函数的一般格式为
Aoperator=(A&
)或着A&
operator=(A&
其中A为类;
operator为关键字;
“=”为重载运算符;
重载憾事有一个参数为类A的引用;
函数返回值是类A的引用。
在主函数中的表达式t=s;
,其中s和t是类point的2个对象。
s为已初始化的对象,将s的值赋给对象t;
“=”为被重载的运算符,编译器将表达式解释为t.operator=(s),其含义是调用重载的赋值运算符函数来实现上述操作。
♣使用成员函数方式重载双目运算符,参数是对象本身的数据,不需要用参数输入,而是通过隐含的this指针传入的,即指向该成员函数的对象的指针。
如果是单目运算符,操作数由对象的传入,也就