第 10章 虚函数和多态性
10.1 虚 函 数
10.2 抽 象 类
10.3 虚 析 构 函 数
10.4 多 态所谓多态,是指不同对象对相同消息作出不同的响应。多态是通过继承、
虚函数以及动态联编来实现的。
10.1 虚 函 数
10.1.1 虚函数的定义虚函数是实际上不存在,但确实影响程序某些部分的函数 。 虚函数有多态性,即派生的类有共同的函数,这些共同的函数有着相同的函数名称和相同的参数,但是却有各自不同的具体实现部分 。
虚函数的定义方法如下:
virtual <函数返回类型 ><虚函数名称 ><
( 参数列表 ) >;
定义虚函数要遵循下列规则:
( 1) 类的静态成员函数不可以定义为虚函数 。
( 2) 类的构造函数不可以定义为虚函数 。
( 3) 非类的成员函数不可以定义为虚函数 。
【 例 10.1】 假设一个程序可用来绘制不同的形状,比如三角形,圆,矩形,椭圆等等,并假设这些类中每个类都有一个成员函数 draw(),通过该函数可绘制对象 。 分析下列程序的输出结果 。
#include "iostream.h"
class person
{
public:
void printInfo() //基类中的函数
{
cout<<"Person\n";
}
};
class worker,public person
{
private:
int kindofwork;
public:
void printInfo ()
//在派生类 worker中重新定义
{
cout<<"Worker\n";
}
};
class teacher,public person
{
private:
int subject;
public:
void printInfo ()
//在派生类 teacher中重新定义
{
cout<<"Teacher\n";
}
};
void main()
{
worker w;
teacher t;
person* p;
p = &w; // w是 worker类对象
p->printInfo();
p = &t;
p->printInfo();
}
程序的执行结果为:
Person
Person
注意,虚函数应该在基类中声明,且不能在派生类中重新定义 。 如果使用派生类层次结构,必须在最高层上声明虚函数 。 虚函数必须定义在它第一次被声明的类中 。
在派生类中重新定义的虚函数必须和基类中的虚函数有相同的参数个数和数据类型,
否则,编译器将认为重载虚函数 。
10.1.2 纯虚函数纯虚函数只有一个函数声明,并没有具体函数功能的实现。可通过给函数指定零值进行声明。纯虚函数的定义格式为:
virtual <函数类型 ><虚函数名称 >
( <参数列表 >) =0
例如:
virtual void getdata() = 0;
不能创建含有一个或多个纯虚函数的类对象,因为如果将函数调用发送给纯虚方法是不会有任何回应的。纯虚函数不可以直接调用,也不可以被继承。
【例 10.2】 分析程序执行结果。
#include "iostream.h"
class A
{
public:
virtual void size()=0;
};
class B:public A
{
private:
double x;
public:
void size()
{
if(x>=0) cout<<x<<endl;
else cout<<-x<<endl;
}
B(double xx){x=xx;}
};
class C:public A
{
private:
double x,y;
public:
void size(){cout<<x*x+y*y<<endl;}
C(double xx,double yy){x=xx;y=yy;}
};
void main()
{
B b(-9.8);
C c(6.0,8.0);
b.size();
c.size();
}
输出结果:
9.8
100
10.2 抽 象 类包含一个或多个纯虚函数的类称为 抽象类。
抽象类 只能作为基类被子类继承,不能定义抽象类的对象,其纯虚函数的实现由子类给出。如果一个派生类继承了抽象类,
但是并没有重新定义抽象类中的纯虚函数,
则该派生类仍然是一个抽象类。只有当派生类中所继承的所有纯虚函数都被实现时,
它才不是抽象类。
【例 10.3】 抽象类举例 。
class Shapes
{
public:
virtual void draw() = 0;
//纯虚函数
virtual void rotate(int) = 0;
//纯虚函数
};
class circle,public Shapes
{
private:
double radius;
public:
circle(int r);
void draw() { }
void rotate(int) { }
double area(){return
3.14159*radius*radius; }
double volume(){return
3*3.14159*radius*radius*radius/4;}
};
10.3 虚 析 构 函 数在析构函数前面加上关键字 virtual进行说明,称该析构函数为虚析构函数。
【例 10.4】 分析程序执行结果。
#include "iostream.h"
class A
{
private:
char* a_ptr;
public:
A ()
//构造函数不能是虚函数
{
a_ptr = new char[5];
}
virtual void fun()=0;
//虚成员函数
virtual ~A () //虚析构函数
{
delete[] a_ptr;
cout<<"释放 A ()"<<endl;
}
};
class B,public A
{
private:
char* ptrderived;
public:
B ()
{
ptrderived = new char[100];
}
~B ()
{
delete[] ptrderived;
cout<<"释放 B ()"<<endl;
}
void fun(){}
};
void main()
{
A *ptr = new B;
delete ptr;
}
程序的执行结果为:
释放 B ()
释放 A ()
如果类 A中的析构函数不用虚函数,则输出结果为:
释放 A ()
10.4 多 态
10.4.1 多态的含义多态是通过类的继承,使得同一个函数可以根据调用它的对象类型不同,作出不同的反应,这意味着通过带有相同消息的函数执行不同的过程 。
多态是通过虚函数来实现的,虚函数的使用本质是将派生类类型的指针赋给基类类型的指针,虚函数被调用时会自动判断调用对象的类型,从而做出相应的响应 。
【例 10.5】 分析下面的程序。
#include "iostream.h
class Shapes
{
public:
virtual void draw()
//基类中的函数
{
cout<<"Draw Base\n";
}
virtual double area()
{
return 0;
}
};
class Circle,public Shapes
{
private:
int radius;
public:
void draw() //在派生类中重新定义
{
cout<<"Draw circle";
}
void area()
{
return 3.141593*radius*radius;
}
};
class Square,public Shapes
{
private:
int length;
public:
void draw() //在派生类中重新定义
{
cout<<"Draw square";
}
void area()
{
return length* length;
}
};
void main()
{
Circle c;
Square s;
Shapes* ptr;
ptr = &c;
ptr->draw();
cout<< "Circle area,"<<ptr->area()<<endl;
ptr = &s;
ptr->draw();
cout<< "Square area,"<<ptr-
>area()<<endl;
}
10.4.2 多态的应用
【 例 10.6】 分析程序执行结果 。 设计学生类 student,提供成员函数 kind表示不同类型的学生,定义为纯虚函数;派生 A类学生 student_A,提供成员函数 kind表示 A类学生,派生 B类学生 student_B,提供成员函数 kind表示 B类学生 。 类 student_A和类
student_B都继承学生类 。
#include "iostream.h"
class student
{
public:
virtual void kind()=0;
//定义 student类,成员函数 kind()为纯虚函数 。
};
class student_A:public student
//定义类 student_A继承类 student
{
public:
void kind();
//类 student_A包含成员函数 kind()
};
class student_B:public student
//定义类 student_B继承类 student
{
public:
void kind();
//类 student_B包含成员函数 kind()
};
void student_A::kind() //编写类
student_A和类 student_B的成员函数 kind()
{
cout<<"A类的学生 ! "<<endl;
}
void student_B::kind()
{
cout<<"B类的学生 ! "<<endl;
}
void kind(student *S)
{
S->kind();
}
void main()
{
student_A a1;
a1.kind();
student_B b1;
b1.kind();
cout<<"----------";
cout<<endl;
student *p;
p=&a1;
kind(p);
p=&b1;
kind(p);
}
程序的执行结果如下:
A类的学生 !
B类的学生 !
----------
A类的学生 !
B类的学生 !