1、18 十二月 2023C+面向对象程序设计第六章 多态性与虚函数t6.1 多态性概述t6.2 重载与再定义t6.3 运算符重载t6.4 虚函数t6.5 抽象类18 十二月 2023C+面向对象程序设计6.1 多态性概述t6.1.1 多态的类型t6.1.2 多态的实现18 十二月 2023C+面向对象程序设计6.1.1 多态的类型t多态性是指同一个消息被不同类型的对象接收时产生不同的行为,特点就是一个接口,多个实现。+中多态性按照类型可以分为强制多态、过载多态、包含多态和参数多态四种。l强制多态是指通过语义操作,强制数据做本不属于该类型数据的操作。编译器内部的数据的隐式转换,比如3.0+4操作时
2、转换成3.0+4.0就属于此种类型l重载多态是指函数重载,同名的操作在不同的环境下有不同的行为。前面学习过的普通函数重载和将要学习的类成员函数重载、运算符重载都属于此种类型。l包含多态是指在同一类族中定义于不同类中的同名函数的多态行为。我们本章将要学习的虚函数就属于此种类型。l参数多态是指功能、结构实现相同但所作用于的数据类型不同,也就是数据类型参数化的多态。第七章中的函数模板和类模板就属于此种多态。18 十二月 2023C+面向对象程序设计6.1.2 多态的实现t多态是指同一个消息被不同的对象接收产生不同的行为,因此,多态在实现的时候必须确定消息的操作对象。我们根据消息和对象相结合的时间分为
3、两种:l在程序编译连接阶段完成的,也就是说在编译的过程中确定了消息的操作对象,我们称为静态绑定。l在程序运行阶段完成的,也就是说在程序运行的过程中才确定消息的操作对象,我们称为动态绑定。18 十二月 2023C+面向对象程序设计6.2 重载与再定义t6.2.1 函数的重载t6.2.2 函数的再定义 18 十二月 2023C+面向对象程序设计6.2.1 函数的重载t函数重载是指功能相似,函数名相同但所带参数不同的一组函数。这里的“所带参数不同”既可能是参数的数据类型不同也可能是参数的个数不同。l普通函数的重载。int abs(int val)return val0?val:val;18 十二月
4、2023C+面向对象程序设计6.2.1 函数的重载l类成员函数的重载。class Tdateprivate:int month,day,year;public:Tdate();Tdate(int m,int d,int y);Tdate:Tdate()month=6;day=20;year=2002;coutmonth/day/yearendl;Tdate:Tdate(int m,int d,int y)month=m;day=d;year=y;coutmonth/day/yearendl;18 十二月 2023C+面向对象程序设计6.2.2 函数的再定义t函数的再定义是指派生类新增了和基类中
5、函数名相同,所带参数也相同的成员函数(如果参数不同就属于函数重载)。l派生类中函数再定义的时候,派生类中的函数成员覆盖了基类中的同名函数成员,通过派生类对象调用该函数成员时,调用的是派生类中新增的同名函数成员。要想在派生类中访问基类的同名成员,可以用前面讲过的作用域限定符。l派生类中函数再定义的时候,通过基类指针来访问该函数成员时,访问的是派生类从基类继承的函数成员。18 十二月 2023C+面向对象程序设计6.3 运算符重载t6.3.1 运算符重载的规则t6.3.2 运算符重载为成员函数 t6.3.3 运算符重载为友元函数 18 十二月 2023C+面向对象程序设计6.3.1 运算符重载的规
6、则t运算符重载的规则如下:l只能重载已有的运算符,不能定义新的运算符,也不能改变原有运算符的含义。l运算符的优先级、结合性和操作对象的个数不能改变。l重载的运算符函数参数不能有默认参数,不能全部是预定义数据类型。l绝大部分重载的运算符函数都能被派生类继承,赋值运算符除外。l关系运算符“.”、作用域分辨符“:”、成员指针运算符“*”、sizeof运算符和三目运算符“?:”这五个运算符不能被重载。t运算符重载为类的成员函数的语法形式:18 十二月 2023C+面向对象程序设计6.3.1 运算符重载的规则l运算符重载为类的成员函数和友元函数的语法形式函数返回类型 operator 运算符(形式参数)
7、函数体;函数返回类型 operator 运算符(形式参数)函数体;18 十二月 2023C+面向对象程序设计6.3.2 运算符重载为成员函数t运算符重载为类的成员函数,它就可以访问类的数据成员。使用重载运算符的时候,通过类的对象来调用运算符重载函数。l调用过程是隐式的,看起来和一般的运算表达式一样,程序编译的时候已经转换成对运算符函数的调用;。l运算符操作对象给出是隐式的,一个运算符操作的是对象本身的数据,即this指针指出。18 十二月 2023C+面向对象程序设计6.3.2 运算符重载为成员函数t单目运算符重载应用举例。class MyIntprivate:int m_a;int m_b;
8、public:MyInt(int a,int b);void operator -();void MyInt:operator-()m_a=-m_a;m_b=-m_b;18 十二月 2023C+面向对象程序设计6.3.2 运算符重载为成员函数t双目运算符应用举例。class MyNumprivate:int number;public:MyNum();MyNum(int num);MyNum operator+(MyNum mynum);MyNum MyNum:operator+(MyNum mynum)MyNum temp;temp.number=number+mynum.number;re
9、turn temp;18 十二月 2023C+面向对象程序设计6.3.3 运算符重载为友元函数t运算符重载为类的友元函数也能够访问类的数据成员。只是运算符重载为类的友元函数时,运算符的操作对象都必须通过重载函数的形参传入。t运算符重载为类的友元函数应用举例。18 十二月 2023C+面向对象程序设计6.3.3 类成员的访问控制class Complexprivate:float real,imag;public:Complex()real=0;imag=0;Complex(float r,float i)real=r;imag=i;friend Complex operator+(const
10、Complex&c1,const Complex&c2);Complex operator+(const Complex&c1,const Complex&c2)Complex temp;temp.real=c1.real+c2.real;temp.imag=c1.imag+c2.imag;return temp;18 十二月 2023C+面向对象程序设计6.4 虚函数t6.4.1 一般虚函数成员t6.4.2 虚析构函数18 十二月 2023C+面向对象程序设计6.4.1 一般虚函数成员tC+中的虚函数机制,通过基类指针,就可以使属于同一个类族的不同对象产生不同的行为,从而实现了运行过程中的多
11、态。lC+中声明一般虚函数的语法规则如下:virtual 函数返回类型 函数名(形参)函数体;18 十二月 2023C+面向对象程序设计6.4.1 一般虚函数成员t虚函数应用举例。class Pointprivate:float x,y;public:Point(float px,float py)x=px;y=py;virtual float Area()constreturn 0;class Rectangle:public Pointprivate:float w,h;public:Rectangle(float rx,float ry,float rw,float rh);float
12、Area()const return w*h;18 十二月 2023C+面向对象程序设计6.4.2 虚析构函数 tC+声明虚析构函数的格式与一般析构函数类似,也是在函数返回类型前面加上关键字virtual。lC+中声明一般虚函数的语法规则如下:l类的析构函数声明为虚函数,那么以它为基类派生的所有派生类的析构函数也变成了虚函数。它的好处是,采用一个基类指针就可以调用所有派生类的析构函数,完成不同对象的清理工作。virtual 类名()函数体;18 十二月 2023C+面向对象程序设计6.4.2 虚析构函数t虚析构函数应用举例。class Studentpublic:Student()coutIn
13、 Student constructorendl;virtual Student()coutInStudentdestructorendl;class GraduateStudent:public Studentpublic:GraduateStudent();GraduateStudent();GraduateStudent:GraduateStudent()coutIn GraduateStudent constructorendl;GraduateStudent:GraduateStudent()coutIn GraduateStudent destructorendl;18 十二月 2
14、023C+面向对象程序设计6.5 抽象类t6.5.1 纯虚函数t6.5.2 抽象类18 十二月 2023C+面向对象程序设计6.5.1 纯虚函数t抽象类为一个类族提供了若干公共接口,这些接口是由纯虚函数来声明的。lC+中纯虚函数的声明如下:l纯虚函数实际上就在一般虚函数基础上加了个“=0”,声明为纯虚函数之后,就意味着是类的公共接口,不能再给出函数体的实现。纯虚函数的具体实现代码由派生类给。l出我们可以比较一下虚函数和纯虚函数的区别:一个有函数体,一个没有函数体。virtual 函数返回类型 函数名(形参)=0;18 十二月 2023C+面向对象程序设计6.5.2 抽象类t至少包含有一个纯虚函
15、数的类称为抽象类。抽象类是为了保证一个类族共享一些公共接口,建立统一的操作界面而设计的类。l从抽象类派生的类必须实现抽象类中所有的接口,即给出抽象类中所有纯虚函数的实现,否则它仍然是一个抽象类化对象。l抽象类不能实例化,也就是不能用抽象类来定义一个对象。18 十二月 2023C+面向对象程序设计6.5.2 抽象类t抽象类应用举例。class Pointprivate:float x,y;public:Point(float px,float py)x=px;y=py;virtual float Area()=0;class Rectangle:public Pointprivate:float w,h;public:Rectangle(float rx,float ry,float rw,float rh);float Area()return w*h;Rectangle:Rectangle(float rx,float ry,float rw,float rh):Point(rx,ry)w=rw;h=rh;