放置外部虚拟表
Placing of external virtual tables
摘自Large-Scale C++ Software Design (Lakos),第652页:
问题是,"编译器会将给定类的虚拟表定义存放在哪个唯一的转换单元中?CFRONT(以及许多其他C++实现)采用的技巧是将外部虚拟表放在翻译单元中,该转换单元定义类中出现的词法上第一个非内联函数(如果存在)。
最常用的编译器(GCC 和 Visual C++)仍然如此吗?还是曾经?
GCC 碰巧记录了它的行为如问题 (http://gcc.gnu.org/onlinedocs/gcc/Vague-Linkage.html) 中所述:
VTables
C++虚函数在大多数编译器中使用查找表(称为 vtable)实现。vtable 包含指向类提供的虚函数的指针,并且类的每个对象都包含一个指向其 vtable(在某些多重继承情况下或 vtables)的指针。如果类声明任何非内联、非纯虚函数,则选择第一个作为类的"key 方法",并且 vtable 仅在定义 key 方法的转换单元中发出。
注意:如果所选键方法稍后定义为内联,则 vtable 仍将在定义它的每个翻译单元中发出。确保在类主体中以内联方式声明任何内联虚拟,即使它们未在此处定义。
但是,即使在多个对象文件中可能有多个 vtables 的情况下(如果"key 方法"结果是内联的,则可能会发生这种情况),编译器也会安排尽可能忽略重复项,但如果目标不支持 COMDAT,则重复项最终可能会在最终二进制文件中使用空格:
当与 GNU ld 2.8 或更高版本一起使用时,例如 GNU/Linux 或 Solaris 2,或在 Microsoft Windows 上,复制副本 这些构造将在链接时被丢弃。这被称为 COMDAT 支持。
在不支持 COMDAT 但支持弱符号的目标上,GCC 将使用它们。这样,一个副本将覆盖所有其他副本,但是 未使用的副本仍将占用可执行文件中的空间。
对于不支持 COMDAT 或弱符号的目标,大多数 具有模糊链接的实体将作为局部符号发出以避免 链接器中的重复定义错误。这不会发生在 但是,内联中的本地静态数据,因为具有多个副本将 几乎可以肯定是破坏了东西。
FWIW,GCC 似乎使用以 __ZTV
开头的符号表示 vtable。
就 MSVC 而言,使用 VC++10 进行的一些实证测试(我不认为 MS 记录了该行为)表明,VC 似乎并没有尝试将 vtable 限制为单个对象文件。由于Microsoft知道它可以依赖于支持 COMDAT 部分的链接器,并且由于构造函数是唯一直接使用 vtable 的函数(我相信所有其他 vtable 使用都是间接的,通过对象指针),看起来 VC 只是将 vtable 的副本放在实例化构造函数的任何对象文件中。 对于使用编译器生成的 ctor 的类,这将是构造该类型对象的任何位置。
- 虚拟决赛作为安全
- PowerPC ppc64le上的Gcc Woverloaded虚拟错误
- 如何在C++中获得"静态纯虚拟"功能?
- 在函数内部的声明中初始化数组,并在外部使用它
- C++无法定义虚拟函数 OUTER 类和头文件
- 使外部项目可用于find_package CMake
- C++:Application.cpp中抛出了未解析的外部符号(解决方案在问题的末尾,供未来的读者参考)
- 使用外部SDK工具链文件在VisualStudio上生成项目编译错误
- C++:来自外部文件的Trivia
- 带有未解析外部元素的C++虚拟析构函数
- 排除外部错误R6025-纯虚拟函数调用
- 非常特定的未解决的外部符号type_info ::`vftsable在 /nodefaultlib中使用虚拟函数时
- 虚拟函数未解决的外部错误
- 如何将外部音频流转发到虚拟音频电缆
- 放置外部虚拟表
- C++未解析的外部符号,在2个虚拟抽象方法上有50%的机会
- 从类外部访问专用虚拟函数
- 错误LNK2019未解析的外部符号虚拟类
- c++链接错误2019无法解决的外部符号虚拟错误,因为接口…(?)
- LNK2001:未解析的外部符号"公共:虚拟长__stdcall CTProcessus::Init