当前位置:文档之家› c++第七章讲义

c++第七章讲义

7.1 多态性概述7.2 虚函数

7.3 抽象类7.4 综合实例

7章

多态与虚函数

一种语言若不支持多态,则不能称之为面向对象的程序设计语言。本章要讨论的多态性与前面我们介绍的继承、封装等一样,都是面向对象程序设计语言中的重要特征。多态性与继承是密不可分的,本章所讲的多态性指在继承类中与基类同名、同参数、同类型函数的不同行为。

一般来说,C++语言支持两种不同类型的多态:编译时多态和运行时多态。本章讨论的内容主要集中在运行时多态及其实现。

【7.1 多态性概述】

多态就是指不同的对象接受到相同的消息时产生不同的响应动作,即对应相同的函数名,却执行了不同的函数体(当然,这些函数体还是要事先定义好,以便调用)。

种把程序标示符与和一个存储地址相联系的过程,称为联编(binding,又译为绑定)。

静态联编:指这种联编在编译阶段完成的,由于联编过

程是在程序运行前完成的,所以又称为早期联编。静态联编能够实现编译时多态。动态联编:指这种联编要在程序运行时动态进行,所以

又称为晚期联编。动态联编可以实现运行时多态。

要实现静态联编,在编译阶段就必须确定标示符(如函数名)和代码之间的对应关系。

重载多态:是函数重载。

强制转换多态:不同类型的数据类型进行

混合运算时要进行的强制类型转换。包含多态:指在基类及其派生类族中同名

函数的不同函数实现,及其在运行时的不同响应。编译时多态和运行时多态的严格划分

都是通用多态

都是专用多态

【7.1 多态性概述】

支持两种编译方式

【7.2 虚函数】

例7-1通过基类指针访问派生类对象

EXAMPLE7_01.H

#ifndef EXAMPLE7_01_H

#define EXAMPLE7_01_H

#include

class Base //声明基类Base

{

private:

double dblBaseTest;

public:

Base(double dblInitial=0.0){dblBaseTest=dblInitial;}

~Base(){}

void setBase(double dblSet){dblBaseTest=dblSet;}

double getBase(){return dblBaseTest;}

void display(); //用于显示基类中的私有数据成员};

class FromBase:public Base //从基类Base 以公有派生类FromBase {

private:

double dblFromTest;public:

FromBase(){}

FromBase(double dblInitBase,double dblInitFrom):Base(dblInitBase){dblFromTest=dblInitFrom;}~FromBase(){}

void setFrom(double setFrom){dblFromTest=setFrom;}double getFrom(){return dblFromTest;}

void display(); //显示派生类的私有数据成员};#endif

//类的声明结束

EXAMPLE7_01.CPP //类的实现开始

#include

#include 通过基类指针访问派生类对象例7-1

cout<<″Now in Base class, we display its private number:″<

cout<<″dblBaseTest :″<

}

void FromBase::display()

{

cout<<″Now in FromBase class, we display its private number:″<

cout<<″dblFromTest :″<

}

// 类的实现结束

EXAMPLE7_1.CPP

//主程序开始

#include

#include

void main()

{

Base myBase(1.0);

FromBase myFrom(2.0,3.0);

Base *ptrBase=&myBase; //声明指向基类对象的指针

myBase.display();

ptrBase->display();

myFrom.display();

ptrFrom->display();

ptrBase=&myFrom; //将基类指针指向派生类对象

ptrBase->display();

}

//程序结束

Now in Base class, we display its private number:

dblBaseTest :1.000000

Now in Base class, we display its private number:

dblBaseTest :1.000000

Now in FromBase class, we display its private number:

dblFromTest :3.000000

Now in FromBase class, we display its private number:

dblFromTest :3.000000

Now in Base class, we display its private number:

dblBaseTest :2.000000

//EXAMPLE7_02.H //类的声明及实现开始#ifndef EXAMPLE7_02_H #define EXAMPLE7_02_H #include #include

class Fruit //水果类的声明及其实现{

public:

Fruit(){}~Fruit(){}

virtual void dispFruitName() //用virtual 声明虚函数dispFruitName()

{cout<<″It′s fruit class!″<

//的实现

virtual void eatFruit() //用virtual 声明虚函数eatFruit()

{cout<<″Can not eat an abstract fruit!″<

//现。

};

水果类

例7-2

class Apple:public Fruit //公有派生类Apple

{

private:

char cAppleName[20];

public:

Apple(){}

~Apple(){}

void getAppleName(char applename[20]){strcpy(cAppleName,applename);} void dispAppleName(){cout<<″The apple name is:″<

//虚函数dispFruitName()的实现void eatFruit(){cout<<″Oh,it′s some acid!″<

//eatFruit()的实现

};

class Orange:public Fruit //公有派生类Orange

{

private:

char cOrangeName[20];

public:

Orange(){}

~Orange(){}

void getOrangeName(char orangename

[20]){strcpy(cOrangeName,orangename);}

void dispOrangeName(){cout<<″The orange name is:″<

void dispFruitName(){cout<<″The fruit name is orange.″<

void eatFruit(){cout<<″Haha,it′s sweet!″<

// eatFruit()的实现};

#endif

//类的声明及实现结束

//EXAMPLE7_2.CPP

//主程序开始

#include

#include ″EXAMPLE7_02.H″

void main()

{

Apple myapple,*ptrapple; //声明苹果类的对象及指针Orange myorange,*ptrorange; //声明橘子类的对象及指针myapple.getAppleName(″Guoguang″);

myorange.getOrangeName(″Huangyan″);

ptrfruit=&myfruit;

ptrapple=&myapple;

ptrorange=&myorange;

ptrfruit->dispFruitName();

ptrfruit->eatFruit();

ptrapple->dispFruitName();

ptrapple->dispAppleName();

ptrapple->eatFruit();

ptrorange->dispFruitName();

ptrorange->dispOrangeName();

ptrorange->eatFruit();

ptrfruit=ptrapple; //将基类指针指向派生类对象ptrfruit->dispFruitName(); //执行派生类的成员函数

ptrfruit->eatFruit();

ptrfruit=ptrorange; //将基类指针指向派生类对象

ptrfruit->dispFruitName(); //执行派生类的成员函数

ptrfruit->eatFruit();

}

//主程序结束

说明:声明了基类指针,就可以使不同的派生类对象产生不同

的函数调用,实现了程序的运行时多态。运行时多态应该使用

虚函数,并通过指针、引用或者成员函数调用虚函数。

It′s fruit class!

Can not eat an abstract fruit!The fruit name is apple.

The apple name is:Guoguang Oh,it′s some acid!

The fruit name is orange.

The orange name is:Huangyan Haha,it′s sweet!

The fruit name is apple.

The apple name is:Guoguang Oh,it′s some acid!

The fruit name is orange.

The orange name is:Huangyan Haha,it′s sweet!

声明虚成员函数的语法是正如上例中我们所看到的:

virtual 函数类型函数名称(形式参数表);

虚函数的声明只能出现在类声明时的函数原型声明中。在派生类中可注

(续)

【7.3 抽象类】

函数无法具体实现(或不必实现)。这样的函数可以声明为纯虚函数。对于纯虚函数,可以不必定义它的函数体。含有纯虚函数的类被称为抽象类。

设计抽象类的目的就是为了多态地使用它的成员函数,由此为整个类族规定统一的接口形式。

纯虚函数的语法形式是:

virtual 函数类型函数名(参数表)=0;

特点是在函数名及参数表后面多了一个“=0”。

一旦在基类中声明了纯虚函数,该基类就成为抽象类,若该类的某个派生类没有给出基类中的纯虚函数的全部实现,则该派生类依然是抽象类。

可以声明指向抽象类的指针,虽然该指针不能指向任何抽象类的对象(因为不存在),但可以通过该指针获得对派生类成员函数的调用。#ifndef EXAMPLE7_03_H #define EXAMPLE7_03_H #include #include class Fruit //声明抽象类{public:

Fruit(){}~Fruit(){}

virtual void dispFruitName()=0; //声明为纯虚函数virtual void eatFruit()=0; //声明为纯虚函数};

class Apple:public Fruit //派生类为非抽象类改进后的水果类——抽象类

说明:水果本身是一个抽象的概念。所以可以考虑用抽象类来实现水果类。例7-3

private:

char cAppleName[20];

public:

Apple(){}

~Apple(){}

void getAppleName(char applename[20]){strcpy(cAppleName,applename);} void dispAppleName(){cout<<″The apple name is:″<

//中的纯虚函数void eatFruit(){cout<<″Oh,it′s some acid!″<

//函数

};

class Orange:public Fruit //派生类为非抽象类

{

private:

char cOrangeName[20];

public:

Orange(){}

~Orange(){}

void getOrangeName(char orangename

[20]){strcpy(cOrangeName,orangename);}

void dispOrangeName(){cout<<″The orange name is:″<

void dispFruitName(){cout<<″The fruit name is orange.″<

//类中的纯虚函数void eatFruit(){cout<<″Haha,it′s sweet!″<

//数};

#endif

//主程序

#include

#include ″EXAMPLE7_03.H″

void main()

{

Fruit *ptrfruit; //声明指向虚基类的指针

Apple myapple;

Orange myorange;

myapple.getAppleName(″Guoguang″);

myorange.getOrangeName(″Huangyan″);

ptrfruit=&myapple; //将虚基类指针指向派生类的对象ptrfruit->dispFruitName();

ptrfruit->eatFruit();

ptrfruit=&myorange; //将虚基类指针指向派生类对象ptrfruit->dispFruitName();

ptrfruit->eatFruit();

}

The fruit name is apple.

The apple name is:Guoguang

Oh,it′s some acid!

The fruit name is orange.

The orange name is:Huangyan

Haha,it′s sweet!

求不同类型图形的位置和面积

//EXAMPLE7_04.H //类声明

#ifndef EXAMPLE7_04_H #define EXAMPLE7_04_H #include #include

class Shape //声明抽象类作为基类

{

protected:

double x;

double y;

public:

Shape(){}

Shape(double xx,double yy);~Shape(){}

virtual void dispName()=0; //声明纯虚函数virtual void dispArea()=0; //声明纯虚函数virtual void dispPos()=0; //声明纯虚函数};

说明:在基类中声明3个虚函数,dispName(),dispArea()和dispPos()。这些虚函数在其派生类Circle 和Rectangle 中获得不同的实现。例7-4

class Circle:public Shape //声明派生类Circle

(续){

private:

double radius;

double area;

public:

Circle(double cx=1,double cy=1,double rad=1);

~Circle();

void dispName();

void dispArea()

void dispPos();

};

class Rectangle:public Shape //声明派生类Rectangle

{

private:

double length;

double width;

double area;

public:

相关主题
文本预览
相关文档 最新文档