1.4 多态的应用——完善类的初始化和输出功能。
项目一:面向对象程序设计——简单的图书管理系统 模块4:多态的应用
在上一节完成对多本图书的增删查改功能的基础上,应用函数重载和运算符重载进一步完善类的初始化和输出功能。
1.4.1主要知识点
重载,就是重新赋予新的含义?函数重载就是对一个已有的函数赋予新的含义,使之实现新功能?
运算符也可以重载?实际上,我们已经在不知不觉之中使用了运算符重载?
现在要讨论的问题是: 用户能否根据自己的需要对C++已提供的运算符进行重载,赋予它们新的含义,使之一名多用? 1.函数重载
函数重载即重载函数。
重载函数是函数的一种特殊情况,为方便使用,C++允许在同一范围中声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同,也就是说用同一个运算符完成不同的运算功能。这就是重载函数。重载函数常用来实现功能类似而所处理的数据类型不同的问题。
两个重载函数必须在下列一个或两个方面有所区别: 1、函数有不同参数。 2、函数有不同参数类型,
C++的这种编程机制给编程者极大的方便,不需要为功能相似、参数不同的函数选用不同的函数名,也增强了程序的可读性
比如我们要编写一个函数来求一个数的绝对值,然而整数、浮点型数、双精度型数都有绝对值,但为它们编写的函数返回值类型却是各不相同的。比如: int iabs(int a); float fabs(float a); double dabs(double a);
这样是不是有点备了多种开瓶器的感觉?我们能不能在程序设计中也做一个多功能的开瓶器,把所有数据类型的求绝对值都交给abs这一个函数呢?
在C++中,我们也能够把具有相同功能的函数整合到一个函数上,而不必去写好多个函数名不同的函数,这叫做函数的重(音chóng)载(Overload)。重载的本质是多个函数共用同一个函数名。
我们先来看一个函数重载的实例:(程序6.3) #include \
int abs(int a);//当参数为整型数据时的函数原型
float abs(float a);//当参数为浮点型数据时的函数原型
double abs(double a);//当参数为双精度型数据时的函数原型 int main() {
int a=-5,b=3;
float c=-2.4f,d=8.4f; double e=-3e-9,f=3e6;
cout <<\输出函数返回的结果 cout <<\ cout <<\ return 0; }
int abs(int a)//函数定义 {
cout <<\显示运行了哪个函数
return (a>=0?a:-a);//如果a大于等于零则返回a,否则返回-a。 }
float abs(float a) {
cout <<\ return (a>=0?a:-a); }
double abs(double a) {
cout <<\ return (a>=0?a:-a); }
运行结果: int abs int abs a=5 b=3 float abs float abs c=2.4 d=8.4 double abs double abs e=3e-009 f=3e+006
运行结果表明,abs函数果然能够处理三种不同数据类型的数据了。那么我们怎样才能自己造一个“多功能工具”呢?
其实要编写一个重载函数并不是很麻烦。首先,我们要告诉电脑,同一个函数名存在了多种
定义,所以,我们要给同一个函数名写上多种函数原型(如程序6.3的第二到第四行);其次,我们要对应这些函数原型,分别写上这些函数的定义(如程序6.3的主函数体之后,对三个abs函数的定义)。 2.运算符重载
运算符重载的方法是定义一个重载运算符的函数,在需要执行被重载的运算符时,系统就自动调用该函数,以实现相应的运算?也就是说,运算符重载是通过定义函数实现的?运算符重载实质上是函数的重载?
重载运算符的函数一般格式如下:
函数类型 operator 运算符名称 (形参表列) { 对运算符的重载处理 }
在C++中不能在程序中直接用运算符“+”对复数进行相加运算?想将“+”用于Complex类(复数)的加法运算,用户必须自己设法实现复数相加?例如用户可以通过定义一个专门的函数来实现复数相加?或者,编写重载运算符“+”的函数,函数的原型可以是这样的:
Complex operator+ (Complex& c1,Complex& c2);
例:将运算符“+”重载为适用于复数加法,重载函数作为Complex类的友元函数? #include
Complex( ){real=0;imag=0;}
Complex(double r,double i){real=r;imag=i;}
friend Complex operator + (Complex &c1,Complex &c2);//重载函数作为友元函数 void display( ); private: double real; double imag; };
Complex operator + (Complex &c1,Complex &c2) //定义作为友元函数的重载函数 {return Complex(c1.real+c2.real, c1.imag+c2.imag);} void Complex∷display( )
{cout<<″(″< {Complex c1(3,4),c2(5,-10),c3; c3=c1+c2; cout<<″c1=″; c1.display( ); cout<<″c2=″; c2.display( ); cout<<″c1+c2 =″; c3.display( ); } 3.重载流插入运算符和流提取运算符 用户自己定义的类型的数据,是不能直接用“<<”和“>>”来输出和输入的?如果想用它们输出和输入自己声明的类型的数据,必须对它们重载? 对“<<”和“>>”重载的函数形式如下: istream & operator >> (istream &,自定义类 &); ostream & operator << (ostream &,自定义类 &); 即重载运算符“>>”的函数的第一个参数和函数的类型都必须是istream&类型,第二个参数是要进行输入操作的类?重载“<<”的函数的第一个参数和函数的类型都必须是ostream&类型,第二个参数是要进行输出操作的类?因此,只能将重载“>>”和“<<”的函数作为友元函数或普通的函数。 例:用重载的“<<”输出复数? #include Complex( ){real=0;imag=0;} Complex(double r,double i){real=r;imag=i;} Complex operator + (Complex &c2); //运算符“+”重载为成员函数 friend ostream& operator << (ostream&,Complex&); //运算符“<<”重载为友元函数 private: double real; double imag; }; Complex Complex∷operator + (Complex &c2)//定义运算符“+”重载函数 {return Complex(real+c2.real,imag+c2.imag);} ostream& operator << (ostream& output,Complex& c) //定义运算符“<<”重载函数 {output<<″(″< int main( ) {Complex c1(2,4),c2(6,10),c3; c3=c1+c2; cout< (在Visual C++ 6.0环境下运行时,需将第一行改为#include 多分枝结构 循环结构 1.4.2设计思路 1.函数重载在图书管理中的应用 本例中已在前边章节用到了构造函数的重载。使用构造函数的重载,可以使类的初始化功能更完善。具体来做,可以写无参的,一个参数的,两个参数的,带默认值的等各种构造函数,可灵活应用于多种初始化情况。 Book()//构造函数Book()//无参,书名、价格初始化为默认的值 { strcpy(name,\ price=0; }; Book(const char *Name) //重载构造函数,一个参数初始化书名 { strcpy (name,Name); price=0; } Book(const float newPrice) //重载构造函数,一个参数初始化价格 { strcpy(name,\ price=newPrice; } Book(const char *Name,const float newPrice) //重载构造函数,2参数,初始化书名和价格 { strcpy (name,Name); price=newPrice; } 2.运算符重载在图书管理中的应用 重载流插入运算符<<,实现cout对象直接输出一个Book对象(一本图书多个信息项)的功能。 (1)在类中添加流插入运算符<<函数的声明,并声明为友元friend类型。 friend ostream & operator << (ostream & cout1,Book & book) ; //运算符重载方法,输出图书信息 }; (2)定义流插入运算符<<函数 ostream & operator << (ostream & cout1,Book & book) //运算符重载方法,输出图书信息 { cout1< (3)使用流插入运算符<<函数 在显示一本图书信息的功能函数中,直接使用cout<<输出一个Book类对象 void showBook(int i) //输出一本图书 { cout<