而在32位机上指针的大小是4字节,因此*(int*)(&d)取得的是vfptr,即虚表的地址。从而*((int*)*(int*)(&d)+0)是虚表的第1项,也就是Base::f()的地址。事实上我们得到了验证,程序运行结果如下: 这说明虚表的第一项确实是虚函数的地址,上面的VC虚函数的布局也确实木有问题。 但是,接下来就引发了一个...
void* __fun[] = { &Base1::base1_fun1, &Base1::base1_fun2 };constvoid** __vfptr = __fun[0]; 通过上面图表, 我们可以得到如下结论: 更加肯定前面我们所描述的: __vfptr只是一个指针, 她指向一个函数指针数组(即: 虚函数表) 增加一个虚函数, 只是简单地向该类对应的虚函数表中增加一项而已...
Baseb(1000); 可见对象b含有一个vfptr,即vprt。并且只有nonstatic数据成员被放置于对象内。我们展开vfprt: vfptr中有两个指针类型的数据(地址),第一个指向了Base类的析构函数,第二个指向了Base的虚函数print,顺序与声明顺序相同。 这与上述的C++对象模型相符合。也可以通过代码来进行验证: C++ 1 2 3 4 5 6...
通过监视窗口我们发现除了 _b 成员外还有了一个 _vfptr 在 b1 对象中: 对象中的这个 _vfptr 我们称之为虚表指针(virtual function pointer),我们简称其为虚表。 一个含有虚函数的类中都至少有一个像这样的虚函数表指针,虚函数地址都会放到这个表里。 虚函数表是一个函数指针数组,虚函数表存储在数据段上(常量区...
// p 现在是类B对象的一个指针,即Q的地址,而Q中包含了指向B类虚函数表的vfptr指针。因此下面的语句将显示 // “this is vfun in class B” p->vfun(); return 0; } 当然在实际编程中,没有人会象上面那样写程序的。运行结果: 再来一个虚函数和多态性例子: ...
Circle对象中除了z成员变量外,实际上还有一个指针_vfptr放在对象的前面(有些平台可能会放到对象的最后面,这个跟平台有关). 对象中的这个指针叫做虚函数表指针,简称虚表指针,虚表指针指向一个虚函数表,简称虚表,每一个含有虚函数的类中都至少有一个虚表指针。
内部多了一个vfptr(虚函数表指针),并指向vftable(虚函数表) 如果父类中有vfptr,那么子类继承的话会继承vfptr,vftable,在创建对象,即构造函数中会将虚函数表指针vfptr指向自己的虚函数表vftable,此时,如果函数发生了重写,那么在多态时会对原来虚函数表中的函数进行替换,然后就造成了同样一个函数当传入父类和子类时,...
编译器会在虚函数表 vftable 的开头插入一个指针,指向当前类对应的 type_info 对象。当程序在运行阶段获取类型信息时,可以通过对象指针 p 找到虚函数表指针 vfptr,再通过 vfptr 找到 type_info 对象的指针,进而取得类型信息。 编译器在编译阶段无法确定 p 指向哪个对象,也就无法获取*p的类型信息,但是编译器可以在...
1> 0 | {vfptr} 1> 4 | m_x 1> 8 | m_y 1> +--- 1> 1> Base::$vftable@: 1> | &Base_meta 1> | 0 1> 0 | &Base::add 利用指针调用add方法 //取出虚函数表的地址intvfptr=*(int*)a;//取出虚表函数表的第一个函数地址intfptr=*(int*)vfptr;// 有大神看见麻烦告知 auto具体是...
1> 0 | {vfptr} 1> 4 | m_x 1> 8 | m_y 1> +--- 1> 1> Base::$vftable@: 1> | &Base_meta 1> | 0 1> 0 | &Base::add 利用指针调用add方法 //取出虚函数表的地址intvfptr=*(int*)a;//取出虚表函数表的第一个函数地址intfptr=*(int*)vfptr;// 有大神看见麻烦告知 auto具体是...