实验7 运算符重载
一、实验目的
- 了解多态性;
- 掌握算术运算符和关系运算符的重载;
- 掌握运算符重载的方法;
- 掌握作为成员函数的运算符重载和作为友元函数的运算符重载的不同特点。
二、相关知识
1.概念理解
多态是指类族中具有相似功能的不同函数使用同一名称来实现,从而可以使用相同的调用方式来调用这些具有不同功能的同名函数。
C++中的多态的实现形式:函数重载、运算符重载、虚函数等。函数重载是指同一个函数可以操作于不同类型的对象:运算符重载是对已有的运算符赋予多重含义,使用已有运算符对用户自定义类型(比如类)进行运算操作,运算符重载实际上是函数重载;虚函数是实现类族中定义于不同类中的同名成员函数的多态行为。
多态从实现的角度可以分为两类:编译时的多态和运行时的多态,前者是在编译过程中确定了同名操作的具体操作对象,而后者则是在程序运行过程中才动态地确定所针对的具体对象。这种确定操作的具体对象的过程就是联编。
编译时的多态通过静态联编解决,如函数重载或运算符重载,它们在编译、链接过程中,系统就可以根据类型匹配等特征确定程序中操作调用与执行代码的关系,即确定了某一个同名标识到底要调用哪一段程序代码。
运行时的多态通过动态联编实现,虚函数是实现动态联编的基础,若定义了虚函数就可以通过基类指针或引用实现,执行时会根据指针指向的对象所属的类,决定调用哪个函数。虚函数具有继承性,其本质不是重载声明而是覆盖。
纯虚函数是在基类中说明的虚函数,它在该基类中可以不给出函数体,要求各派生类根据实际需要编写自己的函数体。带有纯虚函数的类是抽象类,抽象类的主要作用是通过它为一个类族建立一个公共的接口,使它们能够更有效地发挥多态特性。
2.运算符重载
运算符重载是指同样的运算符可以施加于不同类型的操作数上面,使同样的运算符作用于不同类型的数据导致不同类型的行为。
运算符重载的实质就是函数重载。在实现过程中,首先把指定的运算符表达式转化为对运算符函数的调用,运算对象转化为函数的形参,然后根据实参的类型来确定需要调用的函数,这个过程是在编译过程中完成的。
运算符重载的形式有两种,重载为类的成员函数和重载为类的友元函数。其一般语法为:
<函数类型>operator<运算符>(<参数表>)
{
<函数体;>
}
运算符重载为类的成员函数和运算符重载为类的友元函数,其语法基本相同,但参数的使用有所不同。
在运算符重载为类的成员函数时,对于前置单目运算符S,如果要重载S为类X的成员函数,用来实现表达式S xobj,其中xobj是类X的对象,经过重载后,表达式S xobj就相当于函数的调用xobj.operatorS()。对于后置运算符“++”和“--”,如果要将它们重载为类X的成员函数,用来实现xobj++和xobj--就相当于函数调用xobj.operator++(0)和obj.operator--(0)。
对于双目运算符D,如果要重载为类X的成员函数,实现表达式xobj1 D xobj2,则函数只有一个形参,形参的类型是xobj2所属的类型,经过重载后,表达式xobj1 D xobj2相当于函数调用xobj1.operator D(xobj2)。
在运算符重载为类的友元函数时,对于前置单目运算符S,如果要重载S为类X的友元函数,用来实现表达式S xobj,其中xobj是类X的对象,经过重载后,表达式S xobj就相当于函数的调用operator S(xobj)。对于后置运算符“++”和“--”,如果要将它们重载为类X的友元函数,用来实现xobj++或xobj--。重载后表达式xobj++和xobj--就相当于函数调用operator++(xobj,0)和operator--(xobj,0)。
对于双目运算符D,如果要重载为类X的成员函数,实现表达式xobj1 D xobj2,则函数有两个形参,经过重载后,表达式xobj1 D xobj2相当于函数调用xobj1.operator D(xobj2)。对于运算符重载为友元函数的情况,要在函数类型说明之前使用friend关键字来声明。
运算符重载的规则如下:
(1)C++中的运算符除了少数几个之外,其余全部可以重载,但只能重载C++中已有的运算符;
(2)重载之后的运算符的优先级和结合性都不改变;
(3)不能改变原运算符操作数的个数;
(4)不能改变运算符对预定义类型数据的操作方式。
三、实验内容和步骤
【实例1】调试chapter10例子程序。
【实例2】运算符重载。调试并运行以下程序,注意观察程序设计的基本思路和关键知识点。程序实现的基本功能:
(1)定义分数类Franc,包括分子和分母两个成员;
(2)定义成员函数void FranSimp,化简分数;
(3)定义成员函数void display,显示分数信息;
(4)定义成员函数Franc operator+(Franc &f),实现分数的加法运算;
(5)定义成员函数Franc operator++,实现前置++运算;
(6)定义成员函数bool operator==(Franc &f),实现两个分数相等的判断;
实验7 运算符重载
int h,m,s;
time24 t1(23,59,57);
time24 t2;
t2=t1+4;
t2.get_time(h,m,s);
cout<<"time t2 is "<<h<<":"<<m<<":"<<s<<endl;
}
2.#include <iostream>
using namespace std;
class CFraction
{
private:
int nume; // 分子
int deno; // 分母
public:
CFraction(int nu=0,int de=1):nume(nu),deno(de){}
void simplify();
friend istream& operator >> (istream& input, CFraction& c);
friend ostream& operator << (ostream& output, CFraction& c);
int gcd(int x,int y);
CFraction operator+(const CFraction &c); //两个分数相加,结果要化简
CFraction operator+(); //取正一目运算
CFraction operator-(); //取反一目运算
bool operator>(const CFraction &c);
bool operator<(const CFraction &c);
bool operator==(const CFraction &c);
bool operator!=(const CFraction &c);
bool operator>=(const CFraction &c);
bool operator<=(const CFraction &c);
};
istream& operator >> (istream& input, CFraction& c)
{
char c1;
input >> c.nume >> c1 >> c.deno;
return input;
}
ostream& operator << (ostream& output, CFraction& c)
{
output <<c.nume<<'/'<<c.deno<<endl;
return output;
}
//取最大公约数
int CFraction::gcd(int x,int y)
{
int r;
while(y!=0)
{
r=x%y;
x=y;
y=r;
}
return x;
}
//化简(使分子分母没有公因子)
void CFraction::simplify()
{
int n=gcd(nume,deno);
nume=nume/n;
deno=deno/n;
}
CFraction CFraction::operator+(const CFraction &c) //两个分数相加,结果要化简
{
CFraction c1;
c1.nume=nume*c.deno+c.nume*deno;
c1.deno=deno*c.deno;
c1.simplify();
return c1;
}
CFraction CFraction::operator+() //取正一目运算
{
return *this;
}
CFraction CFraction::operator-() //取反一目运算
{
CFraction c1;
c1.nume=-nume;
c1.deno=deno;
return c1;
}
bool CFraction::operator>(const CFraction &c)
{
int this_nume,c_nume,common_deno;
{
this_nume=nume*c.deno;
c_nume=c.nume*deno;
common_deno=deno*c.deno;
if(this_nume>c_nume&&common_deno>0||this_nume<c_nume&&common_deno<0)
return true;
else
return false;
}
}
bool CFraction::operator<(const CFraction &c)
{
int this_nume,c_nume,common_deno;
{
this_nume=nume*c.deno;
c_nume=c.nume*deno;
common_deno=deno*c.deno;
if(this_nume>c_nume&&common_deno>0||this_nume<c_nume&&common_deno<0)
return false;
else
return true;
}
}
bool CFraction::operator==(const CFraction &c)
{
if(*this!=c)
return false;
else
return true;
}
bool CFraction::operator!=(const CFraction &c)
{
if (*this>c || *this<c)
return true;
else
return false;
}
bool CFraction::operator>=(const CFraction &c)
{
if(*this<c)
return true;
else
return false;
}
bool CFraction::operator<=(const CFraction &c)
{
if(*this>c)
return true;
else
return false;
}
int main()
{
CFraction x,y,s;
cout <<"请按照格式输入一个分数,如6/7"<<endl;
cin>>x;
cout <<"请按照格式输入一个分数,如6/7"<<endl;
cin>>y;
cout<<"x="<<x;
cout<<"y="<<y;
s=x+y;
cout<<"x+y=";
cout<<s;
cout<<x;
if (x>y) cout<<"大于"<<endl;
if (x<y) cout<<"小于"<<endl;
if (x==y) cout<<"等于"<<endl;
cout<<y;
cout<<endl;
system("pause");
return 0;
}
实验体会:
本节课在学习的过程中感觉很难,抽象的不好理解,调试总是出现 bug,在网上找到很多源代码运行了解,构造函数还是理解不了它的厉害,本次上机知道了:1.重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的
2.C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。
重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。