多态:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)
像我们之前学的函数重载和符号重载都是多态现象。例:使用运算符“+”使两个数相加,就是发送一个消息,他要调用operator+函数,对于不同的对象,调用不同的重载函数。
多态性可分为静态多态和动态多态。
静态多态:通过函数重载实现,要求程序在编译时就知道调用函数的全部信息。
动态多态:通过virtual function实现,在程序运行的过程中才动态地确定实现操作所针对的对象,所以他又称为运行时都多态性。
虚函数的作用:允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。下面就让我们看一段代码来加深对虚函数和动态多态的理解:
#include <iostream>
#include <cstring>
using namespace std;
class Student{
public:
Student(int , string , float);
void display();
protected:
int num;
string name;
float score;
};
//Student类成员函数的定义
Student::Student(int n, string na, float s){
num = n;
name = na;
score = s;
}
void Student::display(){
cout<<"num: "<<num<<" name: "<<name<<" score: "<<score<<endl;
}
class Graduate:public Student
{
public:
Graduate(int , string , float, float );
void display();
private:
float wage;
};
//graduate类成员函数的定义
Graduate::Graduate(int n, string na, float s, float w):Student(n,na,s){
wage=w;
}
void Graduate::display(){
Student::display();
cout<<" wage: "<<wage<<endl;
}
//main函数
int main(){
Student stu1(1001, "LiHua", 87.5);
Graduate gra1(2001, "xiaoming", 95, 1200);
Student *pt = &stu1;
pt->display();
pt=&gra1;
pt->display();
system("pause");
return 0;
}
在主函数中,当我们把指针指向graduate创建的对象gra1时调用display函数,打印出来的信息只有学号、姓名、分数而没有工资,这时我们只要在student类中的display函数声明为虚函数即可,即在前面加入virtual关键字。
下面我们来了解下在使用虚函数时需要注意些什么:
只能用virtual声明类中的成员函数,把他作为虚函数,而不能将类外的普通函数声明为虚函数。因为虚函数的作用时允许在派生类中对基类的虚函数重新定义。显然他只能用于类的继承层次结构中。
一个成员函数被声明为虚函数之后,在同一类族中的类就不能再定义一个virtual的但与该虚函数具有相同的参数(包括个数和参数)和函数返回值类型的同名函数。
虚析构函数
当基类的析构函数为虚函数时,无论指针指的是同一类族中的哪一个类对象,系统都会采用动态关联,调用相应类的析构函数,对该对象进行清理工作。
构造函数不能声明为虚函数。这是因为在执行构造函数时类对象还未完成建立过程,当然谈不上把函数与类对象的绑定。
纯虚函数和抽象类
纯虚函数
纯虚函数的作用是在基类中为其派生类保留一个函数的名字,以便派生类根据需要对它进行定义。如果在基类中没有保留函数名字,则无法实现多态性。纯虚函数只有函数的名字而不具备函数的功能,不能被调用。可以说是“徒有其表,,而无其实“。它只是通知编译系统:“在这里声明一个虚函数,留待派生类中定义。在派生类中对此函数提高提供定义后,他才具备函数的功能,可以被调用。”
声明纯虚函数的一般形式:
virtual 函数类型 函数名(参数列表)=0;
抽象类
方式凡是包含是纯虚函数的类都市是抽象类1.一位内。因为纯虚函数是不能被调用的,包含是纯虚函数的类是无法建立对象的。抽象类的作用是作为一个类族的共同基类,或者是说,为一个类族提供一个公共接口。