第21次课运算符重载.docx
《第21次课运算符重载.docx》由会员分享,可在线阅读,更多相关《第21次课运算符重载.docx(11页珍藏版)》请在冰豆网上搜索。
第21次课运算符重载
第21讲
教学内容
8.1多态性概述
8.1.1多态的类型
8.1.2多态的实现
8.2运算符重载
8.2.1运算符重载的规则
8.2.2运算符重载为成员函数
8.2.3运算符重载为友元函数
教学重点和难点
1多态的理解
2运算符重载的作用
3运算符重载的两种形式,了解如何重新定义(重载)运算符以处理新的抽象数据类型
教学方法:
通过举现实生活中的例子,讲解多态的概念。
通过程序举例演示,讲解运算符重载的作用,运算符重载的两种形式
教学学时
2学时
教学过程
一多态:
1多态性是面向对象程序设计的重要特征之一。
2多态性是指发出同样的消息被不同类型的对象接收时有可能导致完全不同的行为。
3多态的实现:
–函数重载
–运算符重载
–虚函数
二运算符重载:
1运算符重载的实质
1)如何将C++中的运算符和类对象结合一起使用,这个过程称为运算符重载(operatorvoerlonding)。
C++允许程序员重载大多数运算符,使其更符合使用场景,编辑器根据运算符的使用方式生成合适的代码。
虽然重载运算符的实现的也可以通过显示函数调用来完成,但是使用重载运算符可以使程序更清晰,针对同样的操作,使用运算符重载比使用显式函数调用更能提高程序的可读性。
对于类对象的运算符必须重载,但赋值运算符(=)无须显式重载就可以用语每个类,其默认行为是类数据成员的逐个赋值,但这种默认行为对带有指针成员的类是危险的,此时可以显式重载赋值运算符。
2)运算符重载是对已有的运算符赋予多重含义
3)必要性
–C++中预定义的运算符其运算对象只能是基本数据类型,而不适用于用户自定义类型(如类)
4)实现机制
–将指定的运算表达式转化为对运算符函数的调用,运算对象转化为运算符函数的实参。
编译系统对重载运算符的选择,遵循函数重载的选择原则。
2运算符重载的规则和限制:
1)可以重载C++中除下列运算符外的所有运算符:
..*:
:
?
:
2)只能重载C++语言中已有的运算符,不可臆造新的。
3)不改变原运算符的优先级和结合性。
重载运算符应该模拟其内部对象的功能。
例如:
+运算符重载后,应该仍然执行加法运算,而不是减法运算。
4)不能改变操作数个数。
5)经重载的运算符,其操作数中至少应该有一个是自定义类型。
(运算符重载不能改变该运算符用于内部类型对象时的作用方式)
三运算符重载的两种形式:
C++为其内部类型提供了丰富的运算符集,重载这些运算符的目的是为用户自定义的类型提供同样简洁的表达式,但运算符的重载不是自动完成的,程序员必须为所要执行的操作编写运算符函数,有时候把这些函数用作成员函数,有时最好用作友元函数,在极少数情况下,他们可能既不是成员函数,也不是友元函数。
1重载为成员函数:
当运算符函数作为成员函数实现时,最左边的操作数必须是运算符类的一个类对象(或者是该类对象的一个引用)。
例如重载运算符(),[],->或者任何赋值运算符时,运算符函数必须声明为类的一个成员函数。
1)声明形式
函数类型operator运算符(形参)
{}
2)重载为类成员函数时
参数个数=原操作数个数-1(后置++、--除外)
3)•双目运算符B
–如果要重载B为类成员函数,使之能够实现表达式oprd1Boprd2,其中oprd1为A类对象,则B应被重载为A类的成员函数,形参类型应该是oprd2所属的类型。
–经重载后,表达式oprd1Boprd2相当于oprd1.operatorB(oprd2)
程序举例:
#include
usingnamespacestd;
classComplex
{
private:
intreal;
intimag;
public:
Complex(intr,inti)
{
real=r;
imag=i;
}
Complex()
{
}
voiddisp()
{
cout<}
Complexoperator+(Complexc2)//将+重载为成员函数,
//参数个数要少一个,因为另外一个参数用了this指针来实现
{
Complextemp;
temp.real=real+c2.real;//this->real
temp.imag=imag+c2.imag;//this->imag
returntemp;
}
};
voidmain(void)
{
Complexc1(1,2);
c1.disp();
Complexc2(3,4);
c2.disp();
Complexc3;
//c3=c1+c2;
//c3=c1.operator+(c2);//与上面c3=c1+c2等价,但上面的写法要简洁清晰些。
//c3=10+c1;//错误!
不能10.operator+(c1)
//c3=c1+10;////错误!
c1.operator+(10)
c3.disp();
}
4)•前置单目运算符U
–如果要重载U为类成员函数,使之能够实现表达式Uoprd,其中oprd为A类对象,则U应被重载为A类的成员函数,无形参。
–经重载后,表达式Uoprd相当于oprd.operatorU()
5)•后置单目运算符++和--
–如果要重载++或--为类成员函数,使之能够实现表达式oprd++或oprd--,其中oprd为A类对象,则++或--应被重载为A类的成员函数,且具有一个int类型形参。
经重载后,表达式oprd++相当于oprd.operator++(0)
++运算符号重载----成员函数
程序举例
#include
usingnamespacestd;
classClock
{
private:
inthour;
intsecond;
intminute;
public:
Clock(inth=0,intm=0,ints=0)
{
hour=h;
second=s;
minute=m;
}
voiddisp()
{
cout<"<"<}
Clockoperator++(int)//重载后置++运算符号为成员函数
{
Clocktemp;
temp=*this;//保存变化之前的值
++(*this);//在后置++运算符函数里面又调用了前置的++函数
returntemp;
}
Clock&operator++()//前置的++运算符号为成员函数,用引用作为函数的返回值
{
second++;
if(second>=60)
{
second=second-60;
minute++;
if(minute>=60)
{
minute=minute-60;
hour++;
if(hour>=24)
{
hour=hour%24;//使小时的值始终保持在0到24之间
}
}
}
return*this;
}
};
voidmain(void)
{
Clockc1(23,59,59);
//c1++;//单独使用的时候,前置和后置是一样的
//c1.disp();
//++c1;
//c1.disp();
//(c1++).disp();
//c1.operator++(0).disp();//与上面的一条语句等价
//(++c1).disp();
//c1.operator++().disp();//与上面的一条语句等价
2重载为友元函数:
如果左边的操作数是不同类的一个对象或者是一个内部类型的对象,该运算符函数必须作为一个非成员函数来实现,如果运算符函数作为非成员函数直接访问该类的private或者protected数据成员,因此出于性能因素考虑,将运算符函数指定为类的友元函数(否则要使用Set或者get函数)。
例如:
重载<<运算符必须有一个ostream&类型的左操作数(如表达式cout<类似重载>>中的cin。
选择非成员函数的另一个原因是使运算符具有可交换性。
例如obj+number和number+obj(如同不同的加法),问题在于,如果作为成员函数重载,类对象必须出现在运算符的左边。
设定为非成员函数不一定是友元函数,只要类的public接口中有相应的set和get函数,set和get函数如果能内联则更好。
1)重载为友元函数时参数个数=原操作数个数,且至少应该有一个自定义类型的形参。
2)如果需要重载一个运算符,使之能够用于操作某类对象的私有成员,可以此将运算符重载为该类的友元函数。
3)函数的形参代表依自左至右次序排列的各操作数。
4)后置单目运算符++和--的重载函数,形参列表中要增加一个int,但不必写形参名。
5)双目运算符B重载后,
表达式oprd1Boprd2
等同于operatorB(oprd1,oprd2)
程序举例:
将+重载为类的友元函数
#include
classComplex
{
private:
intreal;
intimag;
public:
Complex(intr,inti)
{
real=r;
imag=i;
}
Complex()
{
}
voiddisp()
{
std:
:
cout<:
endl;
}
friendComplexoperator+(Complexc1,Complexc2)
//将+重载为友元函数,参数个数跟实际一致
{
Complextemp;
temp.real=c1.real+c2.real;
temp.imag=c1.imag+c2.imag;
returntemp;
}
};
voidmain(void)
{
Complexc1(1,2);
c1.disp();
Complexc2(3,4);
c2.disp();
Complexc3(5,6);
//c3=c1+c2;
//c3=operator+(c1,c2);//与上面等价
//c3.disp();
}
6)前置单目运算符B重载后,
表达式Boprd
等同于operatorB(oprd)
7)后置单目运算符++和--重载后,
表达式oprdB
等同于operatorB(oprd,0)
#include
usingnamespacestd;
classClock
{
private:
inthour;
intsecond;
intminute;
public:
Clock(inth=0,intm=0,ints=0)
{
hour=h;
second=s;
minute=m;
}
voiddisp()
{
cout<"<"<}
friendClockoperator++(Clock&c,int)//重载后置++运算符号为成员函数
{//因为要改变实参的值,所以用引用作为参数
Clocktemp;
temp=c;//保存变化之前的值
++c;//在后置++运算符函数里面又调用了前置的++函数
returntemp;
}
friendClock&operator++(Clock&c1)//前置的++运算符号为成员函数
{
c1.second++;
if(c1.second>=60)
{
c1.second=c1.second-60;
c1.minute++;
if(c1.minute>=60)
{
c1.minute=c1.minute-60;
c1.hour++;
if(c1.hour>=24)
{
c1.hour=c1.hour%24;
}
}
}
returnc1;
}
};
voidmain(void)
{
Clockc1(23,59,59);
//(c1++).disp();
//operator++(c1,0).disp();
//(++c1).disp();
operator++(c1).disp();
}
课后作业