多态性与虚函数

40
多多多多多多多

Upload: kane-ramos

Post on 30-Dec-2015

34 views

Category:

Documents


8 download

DESCRIPTION

多态性与虚函数. 函数重载与静态联编. 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);. 静态联编与动态联编. 静态联编 : 在编译时就能够确定调用哪个函数 动态联编 - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 多态性与虚函数

多态性与虚函数

Page 2: 多态性与虚函数

函数重载与静态联编• void print(char)

• void print(int)

• void print(float)

• void print(char *)

• ……

• print("Hello, overload!");

Page 3: 多态性与虚函数

函数重载与静态联编class MyClass {

public:MyClass();MyClass(int i);MyClass(char c);

);

MyClass c2(34);

Page 4: 多态性与虚函数

静态联编与动态联编

• 静态联编 :– 在编译时就能够确定调用哪个函数

• 动态联编– 在运行时才能够动态确定调用哪个函数

Page 5: 多态性与虚函数

动态联编的基础• C++ 允许指向基类的指针可以指向其派生

类的对象 (down casting)

base *pObj; //base 是一个基类derived derivedObj; //derived 是 base 的派生类

pObj = &derivedObj; // 基类指针可以指向派生类对象

Page 6: 多态性与虚函数

down casting 带来的问题class base {

//...... int function();};class derived: public base {

//......int function();

};pObj->function(); // 调用哪个函数 ?

Page 7: 多态性与虚函数

问题的解决 --virtualclass base {

//...... virtual int function();};class derived: public base {

//...... int function();

};pObj->function(); // 根据 pObj 所指的对

象正确调用相应函数

Page 8: 多态性与虚函数

虚函数的含义• 是一个类的成员函数

• 可以为派生类对象使用,是所有对象的通用实现

• 派生类可以通过编写自己的成员函数来替代基类的虚函数,这种替代是基类预见到的、默认的、甚至是赞成的。

Page 9: 多态性与虚函数

虚函数举例学生( Studen

t)

本科生(UndeGrad)

研究生(PostGrad)

硕士研究生(MastCand)

博士研究生(DoctCand)

Page 10: 多态性与虚函数

class Student {

protected:

char name[30];

int age;

//......

public:

virtual void SelectCourse(); // 选课virtual int CalculateCredit(); // 计算总学分//...

};

Page 11: 多态性与虚函数

//UndeGrad 没有重新实现两个虚函数,// 它使用基类的实现class UndeGrad: public Student {

//......public:

void Practice(); // 工程实践//...

};

Page 12: 多态性与虚函数

//PostUndeGrad 重新实现了两个虚函数class PostGrad: public Student {

//......int superVisorID; // 导师

public:void SelectCourse(); // 选课int CalculateCredit(); // 计算总学分//...

};

Page 13: 多态性与虚函数

//MasterCand 使用 PostGrad 提供的虚函数class MasterCand: public PostGrad {

//......

public:

//...

};

Page 14: 多态性与虚函数

//DoctorCand 重新实现了两个虚函数class DoctorCand: public PostGrad {

//......

public:

void SelectCourse(); // 选课int CalculateCredit(); // 计算总学分

//...

};

Page 15: 多态性与虚函数

void main()

{

Student * s;

// 程序运行过程中动态创建学生对象,可能是以下各种语句// s = new UndeGrad ();

// s = new PostGrad ();

// s = new DoctCand ();

s = new MasterCand ();

s->SelectCourse(); // 调用 PostGrad::Selectcourse()

}

Page 16: 多态性与虚函数

virtual 的含义• virtual 只在类继承时才发挥作用

• virtual 告诉编译器,它所修饰的函数需要动态联编( dynamic binding )。

•在调用该函数时,需要根据对象的实际类型决定使用类继承层次中哪个类的成员函数

Page 17: 多态性与虚函数

使用虚函数的例子// students 存放所有学生的信息

Student * students[300]; // 指针数组int studNum; // 学生数目

// 在程序运行过程中动态建立了 num 个学生对象//students[studNum++] = new DoctCand();

//students[studNum++] = new UndeGrad();

//......

Page 18: 多态性与虚函数

使用虚函数的例子// 所有学生选课void StudentSelectCourse(){

for(int i = 0; i < studNum; i++)students[i]->SelectCourse()

}

Page 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;//......

}

不用虚函数机制的程序非常复杂

Page 20: 多态性与虚函数

虚函数带来的好处• 简化程序

– 可以编写为多种不同对象类型正确工作的代码

• 方便维护– 类层次的修改、实现的修改产生的影响小

• 是多态性的语言实现

Page 21: 多态性与虚函数

多态性• 含义:

– 一个对象在其生存期内可以具有多种形态– 一种调用可以有多种执行方式

• 作用:– 让使用和实现分开,实现了一定的封装– 简化了程序设计,高层操作和低层操作分开

Page 22: 多态性与虚函数

多态性的好处void StudentSelectCourse(){

for(int i = 0; i < studNum; i++)students[i]->SelectCourse()

}

复杂的实现

Page 23: 多态性与虚函数

特殊的虚函数

• 虚析构函数– 保证了对象的正确释放

• 纯虚函数– 必须由派生类定义的虚函数

Page 24: 多态性与虚函数

析构函数

void RemoveAllStudents(){

for(int i = 0; i < studNum; i++) delete students[i];

}调用析构函数

Student::~Student()

Page 25: 多态性与虚函数

虚析构函数class UndeGrad : Student {

//...char * somePersonalInfo;

public:UndeGrad();~UndeGrad();//...... 其它操作函数

};

派生类中动态分配了空间

Page 26: 多态性与虚函数

虚析构函数class Student {

//...

public:

Student();

virtual ~Student();

//...... 其它操作函数};

定义虚析构函数

Page 27: 多态性与虚函数

虚析构函数

void RemoveAllStudents(){

for(int i = 0; i < studNum; i++) delete students[i];

}调用正确的析构函数

Page 28: 多态性与虚函数

虚析构函数• 作用:

– 保证调用正确的析构函数– 保证对象的正确释放– 保证系统资源的合理使用

• 注意:– 构造函数不能是虚函数– 析构函数可以(而且应该)定义为虚函数

Page 29: 多态性与虚函数

纯虚函数class Abstract_Student {

protected:

char name[30];

int age;

//......

public:

virtual void SelectCourse() = 0;

virtual int CalculateCredit() = 0;

//...

};

Page 30: 多态性与虚函数

//UndeGrad 必须实现基类的纯虚函数class UndeGrad: public Abstract_Student {

//......public:

void SelectCourse() ; int CalculateCredit();//...

};

Page 31: 多态性与虚函数

//PostGrad 可以保持两个纯虚函数的定义class Abstract_PostGrad: public Abstract_Student {

//......int superVisorID; // 导师

public:void SelectCourse() = 0;int CalculateCredit() = 0 ;//...

};

Page 32: 多态性与虚函数

//DoctorCand 必须实现两个虚函数class DoctorCand: public Abstract_PostGrad {

//......

public:

void SelectCourse();

int CalculateCredit();

//...

};

Page 33: 多态性与虚函数

纯虚函数• 含义 :– 纯虚函数是将要被派生类实现的函数

• 用法 :– 具有纯虚函数的类不能实例化– 派生类如果还有纯虚函数,则还不能实例化– 能实例化的派生类必须实现所有纯虚函数

• 作用 :– 为抽象基类的定义提供了手段– 为所有派生类设计一个标准接口,方便高层应用逻辑的设计

Page 34: 多态性与虚函数

虚函数的使用

•好处: 多态性

•缺点: 增加运行开销– 每个对象增加一个指针– 调用虚函数时要查表

Page 35: 多态性与虚函数

虚函数的内部实现

nameagestudentID......v-pointer

Student::SelectCoursePostGrad::SelectCourseDoctorCand::SelectCourseStudent::SelectCoursePostGrad::SelectCourseDoctorCand::SelectCourse

v-table学生对象

如果没有虚函数,则对象没有这个特殊成员

Page 36: 多态性与虚函数

虚函数与类层次的关系

A

B C

D E

virtual 只要在基类中说明一次

virtual

Page 37: 多态性与虚函数

虚函数与类层次的关系virtual 关系开始于说明它的那个类A

B C

D E

virtual

Page 38: 多态性与虚函数

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

Page 39: 多态性与虚函数

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

Page 40: 多态性与虚函数

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