购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

第1章
概述

C++是一种多范式编程语言,该语言的核心之一是对象。在C++中,对象具有如下属性。

大小(由sizeof获得该属性)。

对齐限制(由alignof获得该属性)。

存储期(分为automatic、static、dynamic、thread-local)。

生命周期。

类型。

值。

名称(可选)。

“C++对象模型”是C++语言中一个非常重要的概念,它定义了内存中对象的布局和访问方式,包括虚函数、多继承、模板等特性的实现方式,对于理解C++程序的底层实现和进行高效的C++编程有着非常重要的意义。因此,每一个C++程序员都有必要了解C++对象模型的相关知识。

C++对象模型的一个关键特征是虚函数。一个类的虚函数成员是指以virtual开头声明的函数,例如在类Q中声明一个print虚函数:

class Q {
public:
  virtual ~Q() = default;
  virtual void print();
};

C++中多态的实现需要保证一个类继承了另一个声明有虚函数的类,并且继承类型为public,例如类Z继承自类Q:

class Z : public Q {
public:
  void print() override;
};

对于拥有虚函数的类而言,对象模型需要考虑的问题包括虚函数存放的位置、以何种方式存放、如何调用相应的虚函数等。同时,C++对象模型还需要考虑虚函数在多态场景下的实现。

根据“C++之父”本贾尼·斯特劳斯特卢普(Bjarne Stroustrup)的《C++语言的设计和演化》一书,在实现C++多态时,编译器会将对象中的虚函数的地址搜集起来并放到一个表格中,然后在对象中增加一个成员vptr来指向这个拥有虚函数地址的表格;对于类的其他成员函数(包括静态成员函数和非静态成员函数),编译器将其放置在对象内存(即栈或堆中为了存放该对象而分配的内存)之外的某处,一般为进程的代码区;对于定义在类中的非静态数据成员,编译器将其放置在对象内存之中;对于静态数据成员,编译器将其放置在对象内存之外的某处,一般为进程的数据区。例如,更改类Q的定义如下:

class Q {
public:
  virtual ~Q() = default;
  virtual void print();
  void print(int);
  static void need(int);
private:
  static int a_;
  int b_;
};

按照本贾尼所设想的内存模型规则,类Q的对象的内存布局如图1-1所示。

图1-1

为了实现多态,C++又引进了运行时类型识别(Run Time Type Identification,RTTI),此时若类Z公共继承自类Q,则类Z的对象的内存布局如图1-2所示。

图1-2

随着不同编译器的出现,相应的C++对象模型的实现也有所变化,但总体上均是基于本贾尼设计的方案进行变动。

本书主要研究的是GCC/Clang编译器针对C++对象模型的实现。在GCC和Clang编译器中,C++对象模型均是基于Itanium C++ ABI实现的,因此GCC中的C++对象模型的实现均可应用于Clang编译器。本书将围绕GCC展开,讲解其C++对象模型的实现。 u4il6fO3w/306Mw5i0DWAGy2TMXpHGqXPlrFM2/vcbqKgdO1GXwF7T08qU3sBAFH

点击中间区域
呼出菜单
上一章
目录
下一章
×

打开