假设一个人继承了一个复杂的代码库(在Visual C++中,假设2003或者更晚),它具有大而复杂的继承图.假设它很深,并且有很多虚函数,甚至可能还有多重继承.(是的,有点像维护噩梦).任何将此类层次结构重构为更合理的尝试都需要知道每个类使用的每个虚函数的哪个实现.
如果我们采用任意叶类L1 - 它派生自基类B1,它派生自基类B2等 - 它将显然具有类的vtable,它将显示类似于(伪vtable)的类:
L1::F1 B3::F2 B1::F3 L1::F4 etc.
...具体取决于哪个类被哪些虚函数覆盖了.
怎么能看到像这样的形式的vtable呢?可以通过阅读代码手动重建它,但这很容易出错且费力.据推测,在调试器中打破类的对象可能允许您通过该类的vtable指针检查Watch窗口中的vtable,但这是一个尴尬的解决方案,特别是如果您还想查看L2的vtable, L3,... LN.
DbgHelp.dll是否提供了以编程方式检查vtable的工具(允许以任何形式输出)?还是有其他方法吗?
使用Visual Studio 2005,有两个未记录的标志可以完全满足您的需要.它们是reportAllClassLayout和reportSingleClassLayout标志.例如,在cl.exe命令行上尝试"/ d1 reportAllClassLayout".它将向您展示包括虚拟表的完整类布局,这是一个示例.另见http://blogs.msdn.com/vcblog/archive/2007/05/17/diagnosing-hidden-odr-violations-in-visual-c-and-fixing-lnk2022.aspx 没有太多信息在这些标志上,因为它们目前没有记录,但也许微软将在未来版本的visual studio中正式支持它们.
另一种方法,实际上我更喜欢的是使用IDA Pro Interactive反汇编程序.有一个巨大的学习曲线,但IDA足够聪明,可以帮助您构建VTable并将它们链接到您的类.它用于对传统上没有符号的二进制文件进行反向工程,但它也使用visual studio pdb文件.这样做你会看到究竟是什么所有的虚函数表的样子.在逐步执行代码时,哪些虚拟表用于哪些方法或被覆盖的方法.换句话说,您实际上在运行时调试期间看到您的方法调用被追踪到vtable中.正如您所注意到的,VS调试器等典型调试器不会跟踪到虚拟表.