C++虚函数

来源:互联网 发布:淘宝孕妇装店铺排行 编辑:程序博客网 时间:2024/06/05 16:10
虚函数是动态多态性的基础,其调用的方式是动态联编(又称晚期联编,简单解释为只有在程序运行时才决定调用基类的还是子类的,系统会根据基类指针所指向的对象来决定要调用的函数);

非虚函数与其相反,是静态联编(调用已经在编译时期就决定了;在编译时期,系统已经根据指针所属的类型确定了要调用的函数)。

在具体看虚函数前,我们先看一个例子:

头文件定义

#pragma onceclass Shape{public:Shape();~Shape();void draw();};class Rectangle : public Shape{public:Rectangle();~Rectangle();void draw();};class Circle : public Shape{public:Circle();~Circle();void draw();};

源文件实现

#include <iostream>#include "shape.h"using namespace std;Shape::Shape(){}Shape::~Shape(){}void Shape::draw(){cout<<"绘制图形..."<<endl;}Rectangle::Rectangle(){}Rectangle::~Rectangle(){}void Rectangle::draw(){cout<<"绘制矩形..."<<endl;}Circle::Circle(){}Circle::~Circle(){}void Circle::draw(){cout<<"绘制圆形..."<<endl;}

测试文件

#include "shape.h"int main(){Shape *shape;shape = new Rectangle();shape->draw();shape = new Circle();shape->draw();return 0;}

看看运行结果:


是不是和咱们预期的不一样!所以才有了虚函数,下面对上面的程序进行改造。

修改头文件类声明:

#pragma onceclass Shape{public:Shape();~Shape();void virtual draw();};class Rectangle : public Shape{public:Rectangle();~Rectangle();void draw();};class Circle : public Shape{public:Circle();~Circle();void draw();};

注意:Shape的draw()方法声明为virtual

我们再看运行结果:



虚函数的使用方法(以下内容 摘自《C++面向对象程序》):

(1)在基类用virtual声明成员函数为虚函数。

    这样就可以在派生类中重新定义此函数,为它赋予新的功能,并能方便地被调用。

    在类外定义虚函数时,不必再加virtual。

(2)在派生类中重新定义此函数,要求函数名、函数类型、函数参数个数和类型全部与基类的虚函数相同,并根据派生类的需要重新定义函数体。

    C++规定,当一个成员函数被声明为虚函数后,其派生类中的同名函数都自动成为虚函数。

    因此在派生类重新声明该虚函数时,可以加virtual,也可以不加,但习惯上一般在每一层声明该函数时都加virtual,使程序更加清晰。

    如果在派生类中没有对基类的虚函数重新定义,派生类简单地继承其直接基类的虚函数。

(3)定义一个指向基类对象的指针变量,并使它指向同一类族中需要调用该函数的对象。

(4)通过该指针变量调用此虚函数,此时调用的就是指针变量指向的对象的同名函数。

    通过虚函数与指向基类对象的指针变量的配合使用,就能方便地调用同一类的同名函数,只要先用基类指针指向即可。

    如果指针不断地指向同一类族中不同类的对象,就能不断地调用这些对象中的同名函数。


什么时候应该把一个成员函数声明为虚函数呢?

(1)首先看成员函数所在的类是否会作为基类。然后看成员函数在类的继承后有无可能被更改功能,如果希望更改其功能的,一般应该讲其声明为虚函数。

(2)如果成员函数在类被继承后功能不需要修改,或派生类用不到该函数,则不要把它声明为虚函数。

(3)应该考虑成员函数的调用是通过对象名还是通过基类指针或引用去访问,如果是通过基类指针或引用去访问,则应当什么为虚函数。

(4)有时在定义虚函数时,并不定义其函数体,即函数体是空的。

0 0