16多态

迷思 2018-01-09

多态性:在程序多次执行时,某一确定位置的函数调用执行了不同的函数体。

虚函数

虚函数的定义

1.在成员函数(非静态、非构造函数)原型前加上关键字virtual

2.类的虚函数通过继承向下传递,在派生类中既可以直接继承也可以重定义,重定义时函数原型前可以省略virtual,也可以改变访问模式(不提倡),但必须和原来的虚函数具有相同的返回值类型和参数表

虚函数的调用

用对象指针或对象引用对虚函数的调用、成员函数(构造函数和析构函数除外)的函数体中对虚函数的调用将实行动态绑定,其它对虚函数的调用(如对象名加成员选择运算符、虚函数的调用前加类名和作用域运算符)实行静态绑定

示例

#include <iostream.h>

class A

{public:

virtual void f( )

{cout<<"A::f( ) called"<<endl;}

};

class B:public A

{public:

B( ){f( );} //静态绑定

void g( ){f( ); //动态绑定

A::f( ); //静态绑定

}

};

class C:public B

{public:

void f( )

{cout<<"C::f( ) called"<<endl;}

};

main( )

{C c;

c.g( );

return 0;

}

抽象基类和纯虚函数

实现多态性的前提:

1.需要有共同的基类

2.需要在基类中定义共同的接口

3.接口要定义为虚函数

如果基类的接口没办法实现怎么办?

解决方法:

1.不实现这些接口:纯虚函数

2.包含纯虚函数的类:抽象基类

纯虚函数

1.没有函数体的“初始化为0”的函数

//纯虚函数

virtual double area() const = 0;

2.纯虚函数不需要实现,不能被执行

3.通过定义、重定义或继承获得

抽象类和具体类

1.包含纯虚函数(且未对其重定义)的类不能实例化对象,是抽象类

2.如果一个类不是抽象类,则是具体类。

3.抽象类存在的意义是作为其它类的基类,也叫抽象基类

定义或继承获得纯虚函数示例

#include <iostream.h>

class A

{public:

virtual void f( )=0; //纯虚函数定义

};

class B:public A

{public:

B( ){f( );} //静态绑定,错

void g( ){f( ); //动态绑定

A::f( ); //静态绑定,错

}

}; // 类B继承了类A的纯虚函数f,且没有重定义

class C:public B

{public:

void f( )

{cout<<"C::f( ) called"<<endl;}

};

// 类C继承了类A的纯虚函数f,但对f作了重定义

main( )

{C c;

c.g( );

return 0;

}

通过重定义获得纯虚函数示例

#include <iostream.h>

class A

{public:

virtual void f( )

{cout<<"A::f( ) called"<<endl;}

};

class B:public A

{public:

virtual void f( )=0;

//把虚函数f重定义为纯虚函数,virtual可省略

void g( ){f( );}

};

class C:public B

{public:

void f( )

{cout<<"C::f( ) called"<<endl;}

};

// 类C继承了类A的虚函数f和类B的纯虚函数f,

// 但对f作了重定义

main( )

{C c;

c.g( );

return 0;

}

虚析构函数

1.构造函数的执行顺序:从上到下

2.析构函数的执行顺序:从下到上

3.创建对象时要执行正确的构造函数

4.撤销对象时要执行正确的析构函数

动态对象的创建

new ClassName(…);

ClassName指明了要调用的构造函数

动态对象的撤销

delete 基类指针;

如果基类指针指向的是派生类的对象呢?

解决方案:把析构函数定义为虚函数

对于 delete 基类指针; //该类的析构函数为虚函数

程序会根据基类指针指向的对象的类型确定要调用的析构函数

基类的析构函数为虚函数,所有派生类的析构函数都是虚函数

例子一:虚函数与多态性

//文件base.h,定义基类

#if !defined __BASE__H__

#define __BASE__H__

#include <iostream.h>

class Base

{public:

virtual void show( )

{cout<<"I am Base's object!\n";

}

};

#endif

//文件derived.h,定义类Derived

#if !defined __DERIVED__H__

#define __DERIVED__H__

#include "base.h"

class Derived :public Base

{public:

void show()

{cout<<"I am Derived's object!\n";

}

};

#endif

//文件main.cpp,函数调用的动态绑定

#include "derived.h"

main()

{Base *bPtr, bObj;

Derived dObj;

bPtr= &bObj; //基类指针指向基类对象

bPtr->show(); //用指针调用虚函数,动态绑定

bPtr= &dObj; //基类指针指向派生类对象

bPtr->show(); //用指针调用虚函数,动态绑定

return 0;

}

或者

//修改文件main.cpp,用对象引用调用虚函数

#include "derived.h"

main()

{Derived dObj;

Base bObj, &cObj = dObj;

bObj.show(); //用对象调用虚函数,静态绑定

cObj.show();//用对象引用调用虚函数,动态绑定

return 0;

}

例子二:多态性的应用实例

#include <iostream.h>

class shape

{public:

virtual double area(){return 0.0; }

virtual ~shape(){ }

};

double total(shape *s[],int n)

{double sum=0;

for(int i=0;i<n;i++)

sum+=s[i]->area(); //动态绑定

return sum;

}

class triangle: public shape

{protected:

double H,W;

public:

triangle(double h, double w){H=h;W=w;}

double area(){return H*W*0.5;}

};

class rectangle: public triangle

{public:

rectangle(double h, double w)

:triangle(h,w){ }

virtual double area();

};

double rectangle::area(){return H*W;}

class screen

{private:

shape *s[100];

int n;

public:

screen(){n=0;}

void addshapetoscreen(shape *sp)

{if(n<100)n++;

s[n-1]=sp;

}

double total()

{double sum=0;

for(int i=0;i<n;i++)

sum+=s[i]->area();

return sum;

}

};

main()

{shape *s[100];

s[0]=new triangle(2.2,3.3);

s[1]=new rectangle(2.0,4.0);

cout<< total(s,2) << endl;

screen ss;

ss.addshapetoscreen(s[0]);

ss.addshapetoscreen(s[1]);

cout<<ss.total();

for (int i=0;i<2;i++)

delete s[i];

return 0;

}

//增加新的图形不需要修改total函数和screen类

//增加相关图形类

class circle: public shape

{private:

double radius;

public:

circle(double r)

{radius=r;}

double area()

{return radius*radius*3.14159;}

};

//修改主函数

main()

{shape *s[4];

s[0]=new triangle(2.2,3.3);

s[1]=new rectangle(2.0,4.0);

s[2]=new circle(5.0);

s[3]=new circle(8.0);

cout<< total(s,4) <<endl;

screen ss;

ss.addshapetoscreen(s[0]);

ss.addshapetoscreen(s[3]);

cout<<ss.total();

for (int i=0;i<4;i++)

delete s[i];

return 0;

}

例子三:抽象基类的例子

//文件shape.h,定义抽象基类Shape

#if !defined __SHAPE__H__

#define __SHAPE__H__

#include <iostream.h>

class Shape

{public:

virtual double area() const = 0;

virtual void show() const = 0;

};

#endif

//文件circle.h,定义派生类Circle

#if !defined __CIRCLE__H__

#define __CIRCLE__H__

#include "shape.h"

#define PI 3.1416

class Circle :public Shape

{public:

Circle(double = 0.0,

double = 0.0, double = 1.0);

double area() const;

void show() const;

private:

double x,y;

double r;

};

#endif

//文件circle.cpp,实现类Circle

#include "circle.h"

Circle::Circle(double a,

double b, double c)

{ x = a;

y = b;

r = c;

}

double Circle::area() const

{return PI*r*r;

}

void Circle::show() const

{cout<<"I am a Circle: ";

}

// Circle是具体类

//文件rectangle.h,定义派生类Rectangle

#if !defined __RECTANGLE__H__

#define __RECTANGLE__H__

#include "shape.h"

class Rectangle :public Shape

{public:

Rectangle(double = 1.0, double = 1.0);

double area() const;

void show() const;

private:

double length;

double width;

};

#endif

//文件rectangle.cpp,实现类Rectangle

#include "rectangle.h"

Rectangle::Rectangle(double a, double b)

{ length = a;

width = b;

}

double Rectangle::area() const

{

return length*width;

}

void Rectangle::show() const

{

cout<<" I am a Rectangle: ";

} // Rectangle是具体类

//文件main.cpp,测试类Shape的虚函数

#include "circle.h"

#include "rectangle.h"

void callArea(Shape &obj)

{obj.show(); //动态绑定

cout<<"area = "<<obj.area()<<endl;

} // obj.area()动态绑定

main()

{Circle cir(0.0, 0.0, 2.5);

Rectangle rec(2.4, 5.3);

//能用Shape类声明对象吗?

callArea(cir);

callArea(rec);

return 0;

}

例子四:虚析构函数的例子

//文件employee.h,定义基类Employee

#include <iostream.h>

#if !defined __EMPLOYEE__H__

#define __EMPLOYEE__H__

class Employee

{public:

Employee()

{cout<<"Employee begin!"<<endl;

}

virtual ~Employee()

{cout<<"Employee end!"<<endl;

}

};

#endif

//文件programmer.h,定义派生类Programmer

#include <iostream.h>

#include <string.h>

#include "employee.h"

class Programmer: public Employee

{public:

Programmer(char *str)

{cout<<"Programmer begin!"<<endl;

name = new char[strlen(str)+1];

strcpy(name, str);

}

~Programmer()

{delete [] name;

cout<<"Programmer end!"<<endl;

}

private:

char *name;

};

//文件accountant.h,定义派生类Accountant

#include <iostream.h>

#include "employee.h"

class Accountant: public Employee

{public:

Accountant(int n)

{cout<<"Accountant begin!"<<endl;

age = n;

}

~Accountant()

{cout<<"Accountant end!"<<endl;

}

private:

int age;

};

//文件main.cpp

#include "accountant.h"

#include "programmer.h"

const int MAX = 100;

main()

{ int no;

//声明储存雇员信息的数组

Employee *ptr[MAX], *tptr;

int ENum = 0;

char name[100];

int age;

for (int i=0; i<MAX; i++)

ptr[i] = NULL;

//输入雇员信息

cout<<"Input employees' info:"<<endl;

cout<<"1 --- Programmer"<<endl

<<"2 --- Accountant"<<endl

<<"0 --- exit"<<endl;

cin>>no;

while (no)

{switch (no)

{case 1:

cout<<"Please input name:";

cin>>name;

//创建程序员对象

tptr = new Programmer(name);

ptr[ENum++] = tptr;

break;

case 2:

cout<<"Please input his or her age:";

cin>>age;

//创建会计对象

tptr = new Accountant(age);

ptr[ENum++] = tptr;

break;

default:

break;

}

cout<<"Input another employee's info:“

<<endl;

cout<<"1 --- Programmer"<<endl

<<"2 ---Accountant"<<endl

<<"0 --- exit"<<endl;

cin>>no; }

//撤销所有雇员对象

for (i=0; i<ENum; i++)

{

delete ptr[i];

}

return 0;

}

相关推荐