虚函数是指在多态中,派生类和基类中存在返回类型、名字和参数形式都完全相同的函数,但是实现的函数体不同。
虚函数是多态的基础,没有虚函数就无法实现多态特性。在成员函数前加上一个virtual关键词就可以把函数设置为虚函数 ,当一个成员函数被声明为虚函数后,其派生类中的同名函数都自动成为虚函数。
纯虚函数就是声明后面加上 =0 。
virtual void foo()=0;纯虚函数在基类中只声明不定义,而在派生类中必须要定义。拥有纯虚函数的类成为抽象类,抽象类不能实例化。
虚函数的实现原理
当一个类带有虚函数时,编译系统会为该类构造一个虚函数表(指针数组),存放每个虚函数的入口地址。类创建的对象中,成员变量会占用内存空间,而成员函数是不占用内存空间的,但是如果类里有虚函数,这个对象就会有一个指针(指针大小取决于机器位数,32bit则是4B,64bit则是8B),指向虚函数表。这个指针存放在每个对象占用的内存空间的最前部,目的是可以快速地访问虚函数表。
虚函数表是数组而不是程序代码,因此存放在数据段而不是代码段。
派生类会复制基类的虚函数表。如果自己声明了新的虚函数的话,就会增加自己的虚函数入口地址。如果重写了基类的虚函数的话,那么就会覆盖同一个虚函数的入口地址。然后派生类的对象(无论是基类指针还是派生类指针指向这个对象)调用该虚函数的时候就是使用派生类写的函数内容,而不是基类的函数内容。
参考C++ 之虚函数的实现原理
多态就是一个基类指针指向派生类对象时,他调用的虚函数是子类对象的虚函数。
比如说基类是Shape,派生类是Circle、Square,然后Shape中有一个虚函数area(),作用是求图形的面积,由于派生类Circle和Square求面积的方法不同,因此他们需要各自重写虚函数。如果有两个基类指针分别指向这两个派生类对象,则调用area函数时,返回的是他们各自的面积。
基类指针指向两个继承自同一基类的不同派生对象,调用同一个方法却执行了不同的动作,相当于让父类指针有多种形态,即多态。它是通过继承和虚函数实现的。
#include <iostream> using namespace std; class Shape { public: virtual double area() const = 0; //纯虚函数 }; class Square : public Shape { double size; public: Square(double s) { size = s; } virtual double area() const { return size * size; } }; class Circle : public Shape { double radius; public: Circle(double r) { radius = r; } virtual double area() const { return 3.14159 * radius * radius; } }; int main() { Shape* array[2]; //定义基类指针数组 Square Sq(2.0); Circle Cir(1.0); array[0] = &Sq; array[1] =&Cir; for (int i = 0; i < 2; i++) / { cout << array[i]->area() << endl; } return 0; }关于基类和派生类的指针相互指向的问题有以下的情况。
基类指针可以指向派生类对象,但只能直接引用基类的成员(要想操作派生类的数据成员,需要使用虚函数);派生类指针不可以指向基类对象,否则会引发语法错误。