一、概述
二、类的虚表
class A
{
public:
virtual void vfunc1();
virtual void vfunc2();
void func1();
void func2();private:
int m_data1, m_data2;
};
虚表内的条目,即虚函数指针的赋值发生在编译器的编译阶段,也就是说在代码的编译阶段,虚表就可以构造出来了。
三、虚表指针
*__vptr
,用来指向虚表。这样,当类的对象在创建时便拥有了这个指针,且这个指针的值会自动被设置为指向类的虚表。四、动态绑定
class A
{
public:
virtual void vfunc1();
virtual void vfunc2();
void func1();
void func2();
private:
int m_data1, m_data2;
};
class B :
public A
{
public:
virtual void vfunc1();
void func1();
private:
int m_data3;
};
class C:
public B
{
public:
virtual void vfunc2();
void func2();private:
int m_data1, m_data4;
};
*__vptr
,用来指向自己所属类的虚表。A::vfunc1()
和A::vfunc2()
。B::vfunc1()
函数,故B vtbl的两个指针分别指向B::vfunc1()
和A::vfunc2()
。C::vfunc2()
函数,故C vtbl的两个指针分别指向B::vfunc1()
(指向继承的最近的一个类的函数)和C::vfunc2()
。bObject
。由于bObject
是类B的一个对象,故bObject
包含一个虚表指针,指向类B的虚表。int main() {
B bObject;
}
bObject
。虽然p
是基类的指针只能指向基类的部分,但是虚表指针亦属于基类部分,所以p
可以访问到对象bObject
的虚表指针。bObject
的虚表指针指向类B的虚表,所以p
可以访问到B vtbl。如图3所示。int main()
{
B bObject;
A *p = & bObject;
}
p
来调用vfunc1()
函数时,会发生什么现象?int main()
{
B bObject;
A *p = & bObject;
p->vfunc1();
}
p->vfunc1()
时,会发现p
是个指针,且调用的函数是虚函数,接下来便会进行以下的步骤。p->__vptr
来访问对象bObject
对应的虚表。虽然指针p
是基类A*
类型,但是*__vptr
也是基类的一部分,所以可以通过p->__vptr
可以访问到对象对应的虚表。p->vfunc1()
的调用,B vtbl的第一项即是vfunc1
对应的条目。B::vfunc1()
,所以p->vfunc1()
实质会调用B::vfunc1()
函数。p
指向类A的对象,情况又是怎么样?int main()
{
A aObject;
A *p = &aObject;
p->vfunc1();
}
aObject
在创建时,它的虚表指针__vptr
已设置为指向A vtbl,这样p->__vptr
就指向A vtbl。vfunc1
在A vtbl对应在条目指向了A::vfunc1()
函数,所以p->vfunc1()
实质会调用A::vfunc1()
函数。(*(p->__vptr)[n])(p)
-
通过指针来调用函数 -
指针upcast向上转型(继承类向基类的转换称为upcast,关于什么是upcast,可以参考本文的参考资料) -
调用的是虚函数
五、总结
参考资料
-
《C++ Primer》第三版,中文版,潘爱民等译 -
http://www.learncpp.com/cpp-tutorial/125-the-virtual-table/ -
侯捷《C++最佳编程实践》视频,极客班,2015 -
Upcasting and Downcasting, http://www.bogotobogo.com/cplusplus/upcasting_downcasting.php
原文始发于微信公众号(汇编语言):C++ 虚函数表剖析
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论