虚表vftable,编译器为每一个拥有虚函数的类都建有一张虚函数表,里面存有虚函数的入口指针(地址)。在类对象的内存布局中,先是一个vfptr虚表指针,指向虚表首地址,然后经过偏移量的形式来访问虚表中的地址。html
看许多文章都在那里侃侃而谈,然能实际展现类(对象)内存布局者寥寥,不可见内里实现的终究是借他人文字的空想。now, 咱们来一窥究竟!ios
PS:如何利用VS查看类内存布局见文末连接ide
1. 带虚函数类内存布局函数
2. 发生单继承时,派生类内存布局,先是复制一份基类内存布局,而后是本身的布局(注意内存对齐)。虚表指针指向本身的虚表,派生类虚函数地址若是本身未覆盖,那么就是基类的,不然是本身的函数地址。布局
3. 发生多继承时:先按照继承顺序,从左到右排布基类的布局包括虚标指针,而后排布本身的指针和数据;派生类虚表排布形式是按照继承顺序,是继承来的虚函数,若是有覆盖则换成本身的函数地址;而后是下一个基类,直至基类排布完毕。继承来的多张表是独立的(从内存布局中的多个虚表指针能够看出),且使用首地址+偏移量的形式来访问。测试
4. 发生虚继承时:不管是对象内存排布仍是虚表,虚基类的部分都被放到最后排布,且若是派生类有本身的虚函数则会加在第一个基类的虚表末尾。spa
除vfptr和vftable以外,增长了vbtable 虚基类表(存放继承的虚基类的地址)和 vbptr(指向虚基类表的指针)命令行
测试代码debug


1 #include <iostream> 2 class Base 3 { 4 int a; 5 int b; 6 public: 7 virtual void foo() {}; 8 virtual void bar() {}; 9 virtual void bar2(){}; 10 virtual void bar3(){}; 11 }; 12 13 class Base2 14 { 15 int d; 16 public: 17 virtual void foo() {}; 18 }; 19 20 class Derived : virtual public Base, public Base2 21 { 22 int c; 23 public: 24 //void foo() {}; 25 void bar() override {}; 26 virtual void bar4() {}; 27 }; 28 29 int main() 30 { 31 Base b; 32 Derived d; 33 return 0; 34 }
多态原理?我的理解3d
1. C++多态动态创建在虚函数上,使用virtual关键字指明不要在编译器绑定函数地址,而是在运行时访问虚函数表,即动态绑定。
2. 使用基类指针指向派生类对象且调用虚函数时(前提是派生类覆盖了基类虚函数),运行时该指针指向的地址是派生类对象地址,在派生类对象地址头就是指向虚函数表的vfptr,这张虚表天然是派生类的,而在构造虚表的过程当中该虚函数早就被派生类本身的函数地址所覆盖,因此调用函数天然是派生类的函数。
3. 多态的含义:基类指针能够指向基类对象以及不一样派生类对象,实现了一种写法,多种访问方式的效果,称为多态。
【参考资料】
如何利用VS查看类内存排布:http://www.javashuo.com/article/p-uovgyogi-dm.html
(在VS项目右键属性->C/C++->命令行->添加 /d1 reportAllClassLayout 应用便可,注意debug/release还有平台类型)
C++多态以及虚函数的不错文章:http://www.javashuo.com/article/p-gobzqpwp-ms.html