C++多态性与虚函数
面向对象的三个特征:封装、继承和多态。
什么是多态
多态的意思是一个事物有多种形态,英文单词为polymorphism,向不同的对象发送同一个消息,不同的对象在接收时会产生不同的行为(方法)。也就是说,每个对象可以用自己的方式去相应共同的消息。
例如函数的重载、运算符的重载都是多态现象。
一个生活中的例子,比如学生开学,校长发布一条哪一天开学的信息,不同的对象会产生不同的反应,学生就要准备上学,家长要准备学费,老师也要开始备课,学校食堂开始采购食材,这就是多态性,如果没有多态性的话,校长就需要分别对学生、教师和家长等不同的对象单独发通知。
在C++中,多态性表现形式之一是:具有不同功能的函数可以用同一个函数名,这样就可以实现用一个函数名调用不同内容的函数。
从系统实现的角度来看,多态性分为两类:静多态性和动多态性
静多态性是通过函数重载实现的,动多态性是通过虚函数实现的。
什么是虚函数
C++中的虚函数就是用来解决动态多态问题的,所谓虚函数,就是在基类声明函数是虚拟的,并不是实际存在的,然后在派生类中才正式定义此函数,在程序运行期间,用指针指向某一派生类对象,这样就能调用指针指向的派生类对象中的函数,而不对调用其他派生类中的函数。
例如一个基类学生类有一个display方法,这个方法可以输出学生的基本信息,另外有一个派生类毕业生类,也有display方法,可以输出毕业生的基本信息
class student{
public:
student(int ,string); //对信息进行初始化
void display(); //输出信息的函数
protected:
int num; //学号
string name;
}
student::student(int n,string nam){
num=n;
name=nam;
}
void student::display(){
cout<<"num:"<<n<<endl<<"name:"<<nam;
}
class Graduate:public student{
public:
graduate(int ,string,int); //对信息进行初始化
void display(); //输出信息的函数
protected:
int num; //学号
string name;
int time;
}
graduate::graduate(int n,string nam,int tim){
num=n;
name=nam;
time=tim;
}
void Graduate::display(){
cout<<"num:"<<n<<endl<<"name:"<<nam<<endl<<"time:"<<tim;
}
int main(){
Student stu(1,"A");
Graduate gra(1,"B",2020);
Student *pt=&stu;
pt->display();
*pt=&gra;
pt->display();
return 0;
}
这段代码的结果为;
num:1
name:A
num:1
name:B
可以看出派生类Graduate中的display()方法并没有实现,实现的是student中的display方法,我们只需在student类中的display方法前面加一个virtual,就可以把基类中的函数声明为虚函数,第二次输出的结果就调用了派生类的display方法。
虚函数的使用方法
- 在基类中用virtual声明成员函数为虚函数,在类外定义虚函数是,不必再加virtual
- 在派生类中重新定义此函数,函数名、函数类型、函数参数个数和类型必须与基类的虚函数相同。
- 定义一个指向基类对象的指针变量,并使它指向同一类族中需要调用该函数的对象
- 通过该指针变量调用此虚函数,此时调用的就是指针变量指向的对象的同名函数
什么情况下应当声明虚函数
使用虚函数需要注意以下两点
- 只能用virture声明类的成员函数,把它作为虚函数,而不能将类外的普通函数声明为虚函数,因为虚函数的作用是在派生类中对基类的虚函数重新定义,它只能用于类的继承层次结构中。
- 一个成员函数被声明为虚函数后,在同一类族中的类就不能再定义一个非虚函数但与该虚函数具有相同的参数和函数返回值类型的同名函数。
根据什么把一个成员函数声明为虚函数?
- 首先看成员函数所在的类是否会作为基类,然后看成员函数在类的继承后有无可能被更改功能,如果希望更改其功能,一般将其声明为虚函数
- 如果成员函数在类被继承后功能无须修改,或派生类用不到该函数,则不必把它声明为虚函数
- 应考虑对成员函数的调用时通过对象名还是通过基类指针或引用去访问的,如果通过基类指针或引用去访问,则应当声明为虚函数
- 在定义虚函数时,并不定义其函数体,即函数是空的,他的作用只是定义了一个虚函数名,具体功能由派生类实现
虚析构函数
如果用new运算建立了一个临时对象,若基类中有虚构函数,并且定义了一个指向该基类的指针变量,在程序用delete运算符撤销对象时,会发生一个情况系统只会执行基类的析构函数,而不会执行派生类的析构函数。
#include<iostream>
using namespace std;
class Point{ //定义基类
public:
Point(){}
~Point(){cout<<"executing Pont destructor"<<endl;}
}
class Circle:public Point{
public:
Circle(){}
~Circle(){cout<<"executing Circle destructor"<<endl;}
}
int main(){
Point *p=new Circle;
delete p;
return 0;
}
如果没有使用虚析构函数的话,即使是派生类对象进行delete操作,其运行结果为executing Pont destructor,并没有运行派生类的析构函数,所以我们要利用虚析构函数来完成对派生类的操作
#include<iostream>
using namespace std;
class Point{ //定义基类
public:
Point(){}
virture ~Point(){cout<<"executing Pont destructor"<<endl;}
}
class Circle:public Point{
public:
Circle(){}
~Circle(){cout<<"executing Circle destructor"<<endl;}
}
int main(){
Point *p=new Circle;
delete p;
return 0;
}
此时运行的结果为
executing Pont destructor
executing Circle destructor
纯虚函数
virture 函数类型 函数名 (参数列表)=0
(没什么用)
抽象类
不用来定义对象,只是作为一种基本类型用作继承的类,也称作抽象基类,凡是包含纯虚函数的类都是抽象类

浙公网安备 33010602011771号