对C++虚函数、虚函数表的简单理解

一、虚函数的作用

以一个通用的图形类来了解虚函数的定义,代码如下:

#include "stdafx.h"
#include <iostream>
using namespace  std;

class Graph
{
protected:
    double x;
    double y;
public:
    Graph(double x,double y)
    {    
        this->x=x;
        this->y=y;
    }
    virtual void showArea()
    {
        cout<<"计算图形面积"<<endl;
    }
};


class Rectangle:public Graph
{
public:
    Rectangle(double x,double y):Graph(x,y){};
    virtual void showArea()
    {
        cout<<"矩形面积为:"<<x*y<<endl;
    }
};


class Triangle:public Graph
{
public:
    Triangle(double d,double h):Graph(d,h){};
    virtual void showArea()
    {
        cout<<"三角形面积为:"<<x*y*0.5<<endl;
    }
};


class Circle:public Graph
{
public:
    Circle(double r):Graph(r,r){};
    virtual void showArea()
    {
        cout<<"圆形面积为:"<<3.14*x*y<<endl;
    }
};


int _tmain(int argc, _TCHAR* argv[])
{
    Graph *graph;

    Rectangle rectangle(10,5);
    graph=&rectangle;
    graph->showArea();

    Triangle triangle(5,2.4);
    graph=&triangle;
    graph->showArea();

    Circle circle(2);
    graph=&circle;
    graph->showArea();    
    return 0;
}

输出如下,

image

该代码的作用是,设计不同的类去处理不同的图形,所有类继承于同一个Graph类。但是每个图形类都有一个相同的函数showArea。如果有需求是输出多个图形的面积,如果没有虚函数,就需要给每一种图形设计一个数组,然后每种图形分别处理。但是有了虚函数后,不管是什么图形,都只要设计一个Graph数组,然后调用每个成员的showArea函数即可。

示例代码:

Graph* gArray[3];
    gArray[0] = &rectangle;
    gArray[1] = &triangle;
    gArray[2] = &circle;
    for (int i = 0;i < 3;i++)
    {
        gArray[i]->showArea();
    }

输出结果:

image

为什么会有这样的效果呢?原因就是有虚函数表。

二、虚函数表

调试上面的图形类代码,用IDE里的调试工具查看每个类对象;

image

每个对象(事实上,所有相同的类对象,都共用一个虚函数表)都有一个__vfptr成员数组,这个__vfptr就是虚函数表,偏移在基类和继承类中都是一样的,所以虚函数表可以在基类中访问到。

但是仔细查看上面的图,可以看到,每个对象的虚函数表数组都是指向的不同的地址,分别指向自己类中的虚函数。

所以如果指定graph->showArea()

调用的函数是graph->__vfptr[0]()。

这样就保证每个子类都调用的都是自己对应的虚函数了。

原文地址:https://www.cnblogs.com/Reyzal/p/5596555.html