1 / 40

多态性与虚函数

多态性与虚函数. 函数重载与静态联编. void print(char) void print(int) void print(float) void print(char *) …… print("Hello, overload!");. 函数重载与静态联编. class MyClass { public: MyClass(); MyClass(int i); MyClass(char c); ); MyClass c2(34);. 静态联编与动态联编. 静态联编 : 在编译时就能够确定调用哪个函数 动态联编

kane-ramos
Download Presentation

多态性与虚函数

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 多态性与虚函数

  2. 函数重载与静态联编 • void print(char) • void print(int) • void print(float) • void print(char *) • …… • print("Hello, overload!");

  3. 函数重载与静态联编 class MyClass { public: MyClass(); MyClass(int i); MyClass(char c); ); MyClass c2(34);

  4. 静态联编与动态联编 • 静态联编: • 在编译时就能够确定调用哪个函数 • 动态联编 • 在运行时才能够动态确定调用哪个函数

  5. 动态联编的基础 • C++允许指向基类的指针可以指向其派生类的对象(down casting) base *pObj; //base是一个基类 derived derivedObj; //derived是base的派生类 pObj = &derivedObj; //基类指针可以指向派生类对象

  6. down casting带来的问题 class base { //...... int function(); }; class derived: public base { //...... int function(); }; pObj->function(); //调用哪个函数?

  7. 问题的解决--virtual class base { //...... virtual int function(); }; class derived: public base { //...... int function(); }; pObj->function(); //根据pObj所指的对象正确调用相应函数

  8. 虚函数的含义 • 是一个类的成员函数 • 可以为派生类对象使用,是所有对象的通用实现 • 派生类可以通过编写自己的成员函数来替代基类的虚函数,这种替代是基类预见到的、默认的、甚至是赞成的。

  9. 虚函数举例 学生(Student) 本科生 (UndeGrad) 研究生 (PostGrad) 硕士研究生 (MastCand) 博士研究生 (DoctCand)

  10. class Student { protected: char name[30]; int age; //...... public: virtual void SelectCourse(); //选课 virtual int CalculateCredit(); //计算总学分 //... };

  11. //UndeGrad没有重新实现两个虚函数, //它使用基类的实现 class UndeGrad: public Student { //...... public: void Practice(); //工程实践 //... };

  12. //PostUndeGrad重新实现了两个虚函数 class PostGrad: public Student { //...... int superVisorID; //导师 public: void SelectCourse(); //选课 int CalculateCredit(); //计算总学分 //... };

  13. //MasterCand使用PostGrad提供的虚函数 class MasterCand: public PostGrad { //...... public: //... };

  14. //DoctorCand重新实现了两个虚函数 class DoctorCand: public PostGrad { //...... public: void SelectCourse(); //选课 int CalculateCredit(); //计算总学分 //... };

  15. void main() { Student * s; //程序运行过程中动态创建学生对象,可能是以下各种语句 // s = new UndeGrad (); // s = new PostGrad (); // s = new DoctCand (); s = new MasterCand (); s->SelectCourse(); //调用PostGrad::Selectcourse() }

  16. virtual的含义 • virtual只在类继承时才发挥作用 • virtual告诉编译器,它所修饰的函数需要动态联编(dynamic binding)。 • 在调用该函数时,需要根据对象的实际类型决定使用类继承层次中哪个类的成员函数

  17. 使用虚函数的例子 // students存放所有学生的信息 Student * students[300]; //指针数组 int studNum; //学生数目 //在程序运行过程中动态建立了num个学生对象 //students[studNum++] = new DoctCand(); //students[studNum++] = new UndeGrad(); //......

  18. 使用虚函数的例子 //所有学生选课 void StudentSelectCourse() { for(int i = 0; i < studNum; i++) students[i]->SelectCourse() }

  19. 不用虚函数机制 的程序非常复杂 void StudentSelectCourse() { for(int i = 0; i <studNum; i++) { switch (student[i]->type) { case GRAD: //本科生 student[i]->UndeGrad::SelectCourse(); break; case POST: //研究生 student[i]->PostGrad::SelectCourse(); break; case DOCT: //博士生 student[i]->DoctCand::SelectCourse(); break; //...... }

  20. 虚函数带来的好处 • 简化程序 • 可以编写为多种不同对象类型正确工作的代码 • 方便维护 • 类层次的修改、实现的修改产生的影响小 • 是多态性的语言实现

  21. 多态性 • 含义: • 一个对象在其生存期内可以具有多种形态 • 一种调用可以有多种执行方式 • 作用: • 让使用和实现分开,实现了一定的封装 • 简化了程序设计,高层操作和低层操作分开

  22. 多态性的好处 void StudentSelectCourse() { for(int i = 0; i < studNum; i++) students[i]->SelectCourse() } 复杂的实现

  23. 特殊的虚函数 • 虚析构函数 • 保证了对象的正确释放 • 纯虚函数 • 必须由派生类定义的虚函数

  24. 析构函数 void RemoveAllStudents() { for(int i = 0; i < studNum; i++) delete students[i]; } 调用析构函数 Student::~Student()

  25. 虚析构函数 class UndeGrad : Student { //... char * somePersonalInfo; public: UndeGrad(); ~UndeGrad(); //......其它操作函数 }; 派生类中动态分配了空间

  26. 虚析构函数 class Student { //... public: Student(); virtual ~Student(); //......其它操作函数 }; 定义虚析构函数

  27. 虚析构函数 void RemoveAllStudents() { for(int i = 0; i < studNum; i++) delete students[i]; } 调用正确的析构函数

  28. 虚析构函数 • 作用: • 保证调用正确的析构函数 • 保证对象的正确释放 • 保证系统资源的合理使用 • 注意: • 构造函数不能是虚函数 • 析构函数可以(而且应该)定义为虚函数

  29. 纯虚函数 class Abstract_Student { protected: char name[30]; int age; //...... public: virtual void SelectCourse() = 0; virtual int CalculateCredit() = 0; //... };

  30. //UndeGrad必须实现基类的纯虚函数 class UndeGrad: public Abstract_Student { //...... public: void SelectCourse(); int CalculateCredit(); //... };

  31. //PostGrad可以保持两个纯虚函数的定义 class Abstract_PostGrad: public Abstract_Student { //...... int superVisorID; //导师 public: void SelectCourse() = 0; int CalculateCredit() = 0 ; //... };

  32. //DoctorCand必须实现两个虚函数 class DoctorCand: public Abstract_PostGrad { //...... public: void SelectCourse(); int CalculateCredit(); //... };

  33. 纯虚函数 • 含义: • 纯虚函数是将要被派生类实现的函数 • 用法: • 具有纯虚函数的类不能实例化 • 派生类如果还有纯虚函数,则还不能实例化 • 能实例化的派生类必须实现所有纯虚函数 • 作用: • 为抽象基类的定义提供了手段 • 为所有派生类设计一个标准接口,方便高层应用逻辑的设计

  34. 虚函数的使用 • 好处: 多态性 • 缺点: 增加运行开销 • 每个对象增加一个指针 • 调用虚函数时要查表

  35. 虚函数的内部实现 v-table 学生对象 Student::SelectCourse PostGrad::SelectCourse DoctorCand::SelectCourse Student::SelectCourse PostGrad::SelectCourse DoctorCand::SelectCourse name age studentID ...... v-pointer 如果没有虚函数,则对象没有这个特殊成员

  36. 虚函数与类层次的关系 A virtual virtual只要在 基类中说明一次 B C D E

  37. 虚函数与类层次的关系 virtual关系开始于 说明它的那个类 A B C virtual D E

  38. 虚函数与类层次的关系 A *pA; B b; C *pC; D d; pA = &b; pA->func(); //调用A::func() pC = &d; pC->func(); //调用D::func()

  39. 小结 • 虚函数与函数重载 • 静态联编与动态联编 • 多态性 • 纯虚函数 • 虚析构函数 • 虚函数的实现

  40. 其它虚函数的例子 • 多边形 面积计算 • 电话 拨号方式 • 图形 绘制图形

More Related