后文会用到以下名词,本文中给出它们的定义:

alignment of a type T (or object X)

对齐:一个值A,使得任何具有类型T的对象X的地址满足&X % A == 0的约束。

base class of a class T

基类:当本文档提到base class of a class T时,除非另有说明,它指的是T本身以及那些所有直接或间接、虚或非虚地派生出T的类。另外,我们使用严格基类(或者叫真基类)(proper base class)将T本身排除在列表之外。

Paw5zx个人理解:点击查看更多

base class指是T及其所有父类,而proper base class指的是T的所有父类(不包括T)

basic ABI properties of a type T

基本ABI属性:由基础C ABI决定的一种类型的基本表示属性,包括它的大小、对齐、调用约定(calling conventions)中对其的处理方式以及指向该类型的指针的表示方式。

base object destructor of a class T

基础对象析构函数:一个函数,负责执行T的非静态数据成员和T的非虚直接基类的析构函数。

complete object destructor of a class T

完整对象析构函数:一个函数,除了执行基础对象析构函数所需的操作外,还负责执行T的虚基类的析构函数。

deleting destructor of a class T

删除析构函数:一个函数,除了执行完整对象析构函数的所有操作外,还会调用适当的内存释放函数(如delete运算符)。

direct base class order

直接基类顺序:当将一个类的直接基类视为有序集时,此顺序是它们在声明中的顺序,从左到右。

diamond-shaped inheritance

菱形继承:一个类具有菱形继承,当且仅当它有一个虚基类,该虚基类可以通过多个直接基类的不同继承图路径到达。

Paw5zx个人理解:点击查看更多

菱形继承应该描述的是一个类继承结构,位于顶部的基类可以通过多个路径到达,这个定义本身应该并不严格要求顶端的基类必须是通过虚拟继承的。
对于此定义是否限制顶端基类一定要通过虚拟继承,待验证。此名词的使用在2.9.4 RTTI Layout,阅读完再回来更新此条目。

dynamic class

动态类:需要虚表指针的类(因为它或它的基类有一个或多个虚成员函数或虚基类)

Paw5zx个人理解:点击查看更多

原文:

A class requiring a virtual table pointer (because it or its bases have one or more virtual member functions or virtual base classes) is called a dynamic class.

这里的virtual table pointer应该是泛指任意需要运行时表格指针的情况(vptr和vbptr)

empty class

空类:一个类,没有非静态数据成员(除了空数据成员(empty data member)),没有匿名位域(除了零宽位域),没有虚函数,没有虚基类,没有非空非虚的严格基类。

Paw5zx个人理解:点击查看更多

空类,满足以下条件:

  • 无非静态数据成员:除了空类类型的非静态数据成员以外,没有其他类型的非静态数据成员(可以有静态成员)
  • 无匿名位域:除了宽度为零的位域之外,没有任何匿名位域(零宽位域通通常用于强制对齐,但不存储实际数据)
  • 无虚函数:可以有成员函数,但是不可以是虚函数(因为有虚函数,类内就会有虚表指针,就会有内存占用)
  • 无虚基类:
  • 无非空非虚严格基类:只能非虚继承空类

空类常用于空基类优化(Empty Base Optimization, EBO)

对于空类T,有:sizeof(T) == 1,确保了每个实例都有独立的内存地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//Empty是空类
class EmptyBase
{
// 这是一个空的基类
};

class Empty : public EmptyBase
{
// 这个类继承了一个空的基类,自身也不添加任何新的非静态数据成员或虚函数
void func();
unsigned int : 0; // 未命名的零宽位域
static int a;
};

int main()
{
std::cout << "Size of Empty: " << sizeof(Empty) << std::endl;
return 0;
}

empty data member

空数据成员:空类类型的潜在重叠非静态数据成员

inheritance graph

继承图:继承关系拓扑图,其中节点表示一个类及其所有子对象,用有向边将每个节点与其直接基类相连。

inheritance graph order

继承图顺序:通过深度优先遍历继承图获得的类对象及其所有子对象的顺序,从最派生类的对象到基类对象,其中:

  • 没有节点会被访问超过一次(所有节点被访问次数小于等于1)。(因此,虚基类子对象及其所有基类子对象将只被访问一次)
  • 一个节点的子对象按照它们被声明的顺序访问。(例如,给定class A : public B, public C,首先遍历A,然后是B及其子对象,然后是C及其子对象。)

请注意:遍历可以是先序遍历,也可以是后序遍历。除非另有说明,否则按照先序遍历(派生类在基类之前)。

instantiation-dependent

An expression is instantiation-dependent if it is type-dependent or value-dependent, or it has a subexpression that is type-dependent or value-dependent. For example, if p is a type-dependent identifier, the expression sizeof(sizeof(p)) is neither type-dependent, nor value-dependent, but it is instantiation-dependent (and could turn out to be invalid if after substitution of template arguments p turns out to have an incomplete type). Similarly, a type expressed in source code is instantiation-dependent if the source form includes an instantiation-dependent expression. For example, the type form double[sizeof(sizeof(p))] (with p a type dependent identifier) is instantiation-dependent.

暂略

morally virtual

逻辑虚拟:如果XY的虚基类,或是Y的虚基类的直接或间接基类,那么Y的子对象X就是Y逻辑上的虚基类。

nearly empty class

近似空类:一种包含虚指针,并且除了(可能存在的)虚基类之外没有其他数据的类。具体来说,它:

  • 没有非静态数据成员,没有非零宽的匿名位域;
  • 如果这个类具有直接基类,那么这些基类必须符合三种情况之一或组合:empty,nearly empty,virtual;
  • 最多有一个非虚,近似空的直接基类;
  • 没有任何空,非逻辑虚拟,偏移量非零(在派生类的内存布局中不位于起始位置)的严格基类。

这样的类即使是虚的,也可以是主基类,可以与派生类共享虚指针。(这种类最适合用来做primary base class

Paw5zx个人理解:点击查看更多

近似空类的本质在于它是一个只因虚机制而存在的开销的最小的类。它的核心目的是让ABI能高效复用虚表指针和基类的布局,从而避免无意义的对象体积膨胀。

编译器可以将其他空基类或近似空基类折叠到虚表指针所在的空间(offset 0)

non-trivial for the purposes of calls

A type is considered non-trivial for the purposes of calls if:

  • it has a non-trivial copy constructor, move constructor, or destructor, or
  • all of its copy and move constructors are deleted.

This definition, as applied to class types, is intended to be the complement of the definition in [class.temporary]p3 of types for which an extra temporary is allowed when passing or returning a type. A type which is trivial for the purposes of the ABI will be passed and returned according to the rules of the base C ABI, e.g. in registers; often this has the effect of performing a trivial copy of the type.

暂略

POD for the purpose of layout

布局上的POD类型:通常,如果一个类型是POD类型(详见2003版ISO c++ [basic.types]),则这个类型被认为是布局上的POD类型。

一个类型将不会被视为布局上的POD类型,当它:

  • 是一个POD-struct或POD-union(详见ISO c++ [class]),但其声明的位域宽度大于声明的位域类型,或
  • 是一个数组类型,其元素类型不是布局上的POD类型,或
  • 是一个POD-struct,其具有一个或多个潜在重叠的非静态数据成员。

在本段中引用ISO C++的地方,是指该标准的Technical Corrigendum 1版本。

注意:ISO C++标准已经发布了多个修订版,每个修订版都包含了不同的POD定义。为了确保根据标准的不同版本编译的代码的互操作性,有必要为平台确定一个单一的定义。平台供应商可以选择遵循标准的不同版本,但是默认情况下,此ABI下的POD定义是2003年版本(TC1)中的定义。

绑定到TC1中对POD的定义并不妨碍编译器完全符合后来的修订。本ABI规则内使用POD定义仅用来决定是否在基类子对象的尾部填充中分配对象。随着时间的推移,这些标准已经扩展了POD的定义,而且它们也禁止程序员使用memcpy直接读取或写入基类子对象的底层字节。因此,即使在最保守的解释中,实现也可以在任何在C++98中不是POD类型的类的尾部填充中自由分配对象。本ABI也满足这种情况。

potentially-overlapping subobject

潜在重叠子对象:一个潜在重叠子对象是:

  • 基类子对象,或
  • [[no_unique_address]](C++17)特性声明的非静态数据成员
Paw5zx个人理解:点击查看更多

潜在重叠子对象是指在对象内存布局中,可能与其他子对象共址的部分,包括基类子对象和声明了[[no_unique_address]]的非静态成员变量

primary base class

主基类:对于一个动态类来说,主基类(如果存在的话)是一个与动态类在偏移量0处共享虚表指针的唯一基类。

secondary virtual table

次级虚表:嵌入在派生类虚表中的基类的虚表实例

templated entity

暂略

thunk

thunk:(在此ABI中)thunk是与目标函数相关联的一段代码,它会在控制权转移至目标函数之前被调用,而不是直接调用目标函数,目的是为了修改参数(例如this指针)或环境的其他部分,并且可能在函数返回后执行进一步修改。一个thunk:

  • 可能只包含一条指令,执行后直接过渡到紧随其后的目标函数,或者
  • 可能是一个完整的函数,它有自己的堆栈帧,并对目标函数进行完整的调用。

vague linkage

暂略

virtual table (or vtable)

虚表:一个动态类有一个与之关联的虚表(一个动态类可能有多个虚表实例(多重继承情况下);但不是每个对象一个(对象不拥有独立的虚表,所有相同类型的对象都会共享同一个虚表)),表内存储了有关类的动态属性的信息,例如:虚函数指针,虚基类偏移量等。

virtual table group

虚表组:一个集合,包括类的主虚表以及该类的所有严格基类对应的的次级虚表