每个含有虚函数的类有一张虚函数表(vtbl),虚函数表类似数组,其表中每一项是一个虚函数的地址。也就是说虚函数表的每一项是一个指向虚函数的指针。
没有虚函数的类是不会有虚函数表的。
无论类中包含多少各虚函数,都只有一个虚函数表指针和一张虚函数表,之时表的大小变化。如果是A继承B,B继承C,B和C都有虚函数,那么类A仍然只有一个虚函数指针和一个虚函数表。因为C是基类,该类中有一个指向类里存有所有虚函数的表的指针,B是C的派生类,B类中包含一个指向B类存有所有虚函数的表(虚函数表)的指针(包括B类自己的虚函数还有继承C的虚函数),A又是B的派生类,A类中包含一个指向A类存有所有的虚函数的表的指针(包含A类自己的虚函数和继承B和C的)。
问题:为什么派生类重写了基类的虚函数后,在派生类中仍可以访问基类虚函数,它不是被重写了吗?
虚函数也是函数。子类的函数是可以访问父类的函数的,所以子类可以访问父类的虚函数。这里的说的子类重写了父类的虚函数,是说虚函数表里原本存放父类的虚函数,现在重写成存放子类的虚函数了。当通过vptr访问虚函数时,就会访问子类重写的虚函数。但是,要知道,虚函数也是函数,并不是只能通过vptr才能访问虚函数。也可以向访问普通函数那样,进行访问,这样仅仅就是将虚函数当作普通函数使用,访问的就是该类中虚函数。
当用指向子类的基类指针或引用访问虚函数时,才会通过vptr访问虚函数。子类重写了父类虚函数,就会访问子类的虚函数,否则访问父类的虚函数。