《多态性与虚函数.ppt》由会员分享,可在线阅读,更多相关《多态性与虚函数.ppt(40页珍藏版)》请在三一办公上搜索。
1、C+面向对象程序设计,5.7 基类与派生类的转换,子类型:有一个特定的类型S,当且仅当它至少提供了类型T的行为,则称类型S是类型T的子类型。子类型关系是不可逆的。公有继承方式下可以实现子类型。,5.7 基类与派生类的转换,赋值兼容:不同类型数据之间的自动转换和赋值。基类与派生类对象之间有赋值兼容关系,如果类B是类A的子类型,则:可将类B的对象赋值给类A的对象;可将类B对象的地址赋值给指向类A对象的指针;可将类B对象赋值给类A对象的引用。,5.7 基类与派生类的转换,(1)派生类对象可以向基类对象赋值可用子类(公用派生类)对象对其基类对象赋值,赋值时舍弃派生类自己的成员子类型关系是单向的、不可逆
2、的不能用基类对象对其子类对象赋值同一基类的不同派生类对象之间也不能赋值A a1;B b1;a1=b1;/B是A的公用派生类,5.7 基类与派生类的转换,(2)派生类对象可以代替基类对象向基类对象的引用赋值或初始化A a1;B b1;A/赋值/B是A的公用派生类,A a1;B b1;A/初始化,5.7 基类与派生类的转换,(3)如果函数的参数是基类对象或基类对象的引用,相应的实参可以用子类型对象void fun(A,5.7 基类与派生类的转换,(4)派生类对象的地址可以赋值给指向基类对象的指针变量通过指向基类对象的指针,只能访问派生类中的基类成员,而不能访问派生类增加的成员,5.7 基类与派生类
3、的转换,#include#include using namespace std;class Student public:Student(int n,string nam,float s)num=n;name=nam;score=s;void display()coutendlnum:numendl;coutname:nameendl;coutscore:scoreendl;private:int num;string name;float score;,class Graduate:public Student public:Graduate(int n,string nam,float
4、s,float p):Student(n,nam,s),pay(p)void display()Student:display();coutdisplay();pt=,5.7 基类与派生类的转换,5.8 继承与组合,类的组合:在一个类中以另外一个类的对象作为数据成员。类的组合和继承一样,是软件重用的重要方式。继承是“是”的关系,组合是“有”的关系;继承是纵向的,组合是横向的。,5.8 继承与组合,class Teacher public:.private:int num;string name;char sex;class BirthDate public:.private:int year;
5、int month;int day;,class Professor:public Teacher public:.private:.BirthDate birthday;/组合;void fun1(Teacher/错,6.1 多态性的概念,多态性是面向对象程序设计的一个重要特征。面向对象方法中:多态性是指当不同的对象收到相同的消息时,产生不同的动作。C+程序设计中,多态性是指具有不同功能的函数可以用一个函数名,这样就可以用一个函数名调用不同内容的函数。,6.1 多态性的概念,从系统实现的角度看,分为静态多态性和动态多态性两类。静态多态性(编译时的多态性):在程序编译时,系统就决定调用哪个函数
6、表现形式为函数重载和运算符重载,通过函数重载实现动态多态性(运行时的多态性):程序运行过程中动态地确定操作所指向的对象通过虚函数实现,6.3 虚函数,6.3.1 虚函数的作用,虚函数的作用:允许在派生类中重新定义与基类同名的函数,并可通过基类指针或引用来访问基类和派生类中的同名函数。,6.3.1 虚函数的作用,#include/例6.2-1#include using namespace std;class Student public:Student(int,string,float)num=n;name=nam;score=s;void display()coutnum:numnname:
7、“namenscore:score nn;protected:int num;string name;float score;class Graduate:public Student public:Graduate(int,string,float,float);void display();private:float pay;,void Graduate:display()coutdisplay();pt=,6.3.1 虚函数的作用,6.3.1 虚函数的作用,#include/例6.2-2#include using namespace std;class Student public:S
8、tudent(int,string,float)num=n;name=nam;score=s;virtual void display()coutnum:numnname:“namenscore:score nn;protected:int num;string name;float score;class Graduate:public Student public:Graduate(int,string,float,float);void display();private:float pay;,void Graduate:display()coutdisplay();pt=,6.3.1
9、虚函数的作用,6.3.1 虚函数的作用,把基类的某个成员函数说明为虚函数后,允许在派生类中对该函数重新定义,赋予它新的功能,并可通过基类指针指向不同类的对象,从而调用其中的同名函数。虚函数实现的动态多态性:同一类族中不同类的对象,对同一函数调用作出不同的响应。,6.3.1 虚函数的作用,虚函数的使用方法在基类用virtual声明成员函数为虚函数在类外定义虚函数时,不必再加virtual在派生类中重新定义此函数函数名、类型、参数个数和类型与基类相同当一个成员函数声明为虚函数后,其派生类中的同名函数都成为虚函数派生类中重新声明该虚函数时,可加virtual,也可不加virtual,6.3.1 虚函
10、数的作用,虚函数的使用方法定义一个指向基类对象的指针变量,并使它指向同一类族中的某一对象通过该指针变量调用此虚函数,此时调用的就是指针变量指向的对象的同名函数,关联:一个程序自身彼此关联的过程。静态关联:在程序编译连接阶段进行联编,又称为早期关联。动态关联:程序运行时进行的关联,又称为滞后关联。子类型关系:继承是动态联编的基础虚函数:虚函数是动态联编的关键动态联编要求继承是public,6.3.2 静态关联与动态关联,使用虚函数时,需注意两点:只能将成员函数声明为虚函数一个成员函数声明为虚函数后,在同一类族中的类就不能再定义一个非virtual的但与该虚函数具有相同参数(参数个数和类型)和返回
11、类型的同名函数。,6.3.3 在什么情况下应当声明虚函数,是否把一个成员函数声明为虚函数成员函数所在类是否会作为基类,成员函数在派生类中功能是否修改通过对象名还是通过基类指针或引用调用成员函数,6.3.3 在什么情况下应当声明虚函数,6.3.4 虚析构函数,将析构函数说明为虚析构函数的方法是在析构函数前加virtualclass Bpublic:virtual B();,6.3.4 虚析构函数,#include/例6.3-1using namespace std;class Pointpublic:Point()Point()coutexecuting Point destructorendl
12、;class Circle:public Pointpublic:Circle()Circle()coutexecuting Circle destructorendl;private:int radus;int main()Point*p=new Circle;delete p;/调用基类析构函数 return 0;,6.3.4 虚析构函数,6.3.4 虚析构函数,#include/例6.3-2using namespace std;class Pointpublic:Point()virtual Point()coutexecuting Point destructorendl;class
13、 Circle:public Pointpublic:Circle()Circle()coutexecuting Circle destructorendl;private:int radus;int main()Point*p=new Circle;delete p;/先调用派生类析构函数,再调用基类析构函数 return 0;,6.3.4 虚析构函数,6.3.4 虚析构函数,如果一个基类的析构函数被说明为虚析构函数,则它的派生类中的析构函数也是虚析构函数,可以不在派生类析构函数前加virtual说明符在程序中用delete删除对象时,能确保析构函数被正确地执行。构造函数不可声明为虚函数,6
14、.4 纯虚函数与抽象类,6.4 纯虚函数,纯虚函数:没有具体实现的虚函数,特殊的虚函数。在许多情况下,在基类中不能给出有意义的虚函数定义,这时可以把它说明成纯虚函数,把它的定义留给派生类来做。,6.4 纯虚函数,定义纯虚函数的一般形式为:class 类名 virtual 返回值类型 函数名(参数表)=0;纯虚函数不能被调用派生类都定义自己的虚函数版本如果在一个类中声明了纯虚函数,而在其派生类中没有对该函数定义,则该函数在派生类中仍为纯虚函数,6.4.2 抽象类,抽象类抽象类至少有一个纯虚函数,纯虚函数是抽象类的必要条件。抽象类中的纯虚函数可能是在抽象类中定义的,也可能是从它的抽象基类中继承下来
15、的。抽象类只能用作其他类的基类,抽象类不能建立对象,但仍可使用指向抽象类的指针支持运行时多态性。,6.4.2 抽象类,#include class Pointpublic:Point(int i=0,int j=0)x0=i;y0=j;virtual void Draw()=0;private:int x0,y0;int main()Point p1;return 0;/错,抽象类不能定义对象,6.4.2 抽象类,抽象类不能用作函数参数类型、函数返回值类型或显式转换的类型。可以声明抽象类的指针和引用。,#include class Pointpublic:Point(int i=0,int j
16、=0)x0=i;y0=j;virtual void Draw()=0;private:int x0,y0;class Line:public Pointpublic:Line(int i=0,int j=0,int m=0,int n=0):Point(i,j)x1=m;y1=n;void Draw()coutLine:Draw()called.n;private:int x1,y1;,class Ellipse:public Pointpublic:Ellipse(int i=0,int j=0,int p=0,int q=0):Point(i,j)x2=p;y2=q;void Draw()coutDraw();void main()Line*lineobj=new Line;Ellipse*ellipseobj=new Ellipse;Drawobj(lineobj);Drawobj(ellipseobj);,6.4.3 应用实例,