c++虚表查询
C++ vtable query
我有一个关于这里提供的解释的查询http://www.parashift.com/c++-faq/virtual-functions.html#faq-20.4
在示例代码中,函数mycode(Base *p)
调用virt3
方法为p->virt3()
。在这里,编译器如何确切地知道virt3在vtable
的第三个槽中找到?
当编译器看到Base
的定义时,它根据某种算法1决定其vtable
的布局,就继承自Base
的方法而言,这对所有派生类都是通用的(派生类可以添加其他virtual
方法,但它们被放在vtable
之后继承自Base
的东西)。
因此,当编译器看到p->virt3()
时,它已经知道对于任何从Base
继承的对象,指向正确的virt3
的指针例如在vtable
的第三个槽中(因为它在定义Base
的vtable
时就是这样布局的),因此它可以正确地生成虚调用的代码。
长话短说(从@David Rodríguez的评论中获得灵感):它知道在哪里,因为他之前就决定了。
1. 该标准没有强制要求任何特定的算法(实际上,它没有说明c++ ABI应该如何实现),但是有几个广泛的c++ ABI规范,特别是Windows上的COM ABI和Linux上的Itanium ABI(以及一般的gcc)。显然,给定相同的类定义,算法必须每次都给出相同的虚参表布局,否则不可能将不同的对象模块链接在一起。
虚值表的布局由Itanium c++ ABI指定,包括GCC在内的许多编译器遵循。编译器本身并不决定函数指针的去向(尽管我认为它确实决定遵守ABI!)。
虚表中虚函数指针的顺序与类中相应成员函数的声明顺序一致。
(例子)。
COM本;Visual Studio —还会按源代码顺序发出虚函数表指针(尽管我找不到规范文档来证明这一点)。
而且,因为函数名在运行时甚至不存在(而是一个函数指针),所以在编译时的虚函数表布局并不重要。函数调用转换的工作方式与普通函数调用转换的工作方式完全相同:编译器已经将函数名称映射到其内部机制中的地址。唯一的区别是这里的映射是指向虚函数表中的一个位置,而不是指向实际函数代码的开头。
在某种程度上,这也解决了您对互操作性的关注。
请记住,这些都是实现机制,c++本身甚至不知道虚表的存在。
编译器有一个定义良好的算法来分配虚函数表中的条目,以便无论处理哪个翻译单元,条目的顺序始终是相同的。在编译器内部,函数名和它们在虚值表中的位置之间有一个映射,这样编译器就可以在函数调用和虚值表索引之间进行正确的转换。
因此,更改带有虚函数的类的定义时,必须重新编译依赖于该类的所有源文件,否则可能会发生不好的事情。
- 是否有用于查询 HTML 表的 SQL 包装器
- 虚表中虚函数的地址
- 通过虚表接口使用Excel
- 在静态分配对象上调用虚函数时使用的虚表
- 为什么在析构函数中将虚表设置回该级别
- 编译一个Qt单文件从命令行:未定义的引用到虚表
- Qt与代码块-未定义的引用虚表
- 在多重继承中,被重写的虚方法保存在c++的虚表中
- 对虚表的未定义引用.Q_OBJECT宏
- 在c++中禁用虚函数的动态绑定(创建虚表)
- 尽管没有虚函数,对虚表的未定义引用
- c++虚表查询
- 虚表的顺序重要吗?
- 对虚表、构造函数和析构函数的未定义引用
- 我试图访问一个c++多态类的虚表,但失败的核心转储,为什么
- 对虚表的未定义引用
- 不带虚表的c++动态分派
- 为什么在虚表中需要一个纯虚函数表项
- 未定义对类的虚表的引用
- 虚表/调度表