WRY

Where Are You?
You are on the brave land,
To experience, to remember...

0%

《深度探索C++对象模型》读书笔记

废弃,请参考

关于对象

对象实际需要的内存大小

  • nonstatic data members 总和大小
  • 由于alignment需求和填补(padding)上去的空间
  • 为了支持virtual而由内部产生的任何额外负担

指针类型

通过指针类型教导编译器如何解释某个地址中的内存内容及其大小。

  • 指向1000的int 类型的指针,在32位(int是4-bytes)的机器上,涵盖1000-1003的地址空间
  • 指向1000的string类型指针,是8-bytes,包括一个4-bytes的字符指针和一个用来表示字符串长度的整数

所以cast操作是一种编译器指令,它只影响被指出内存的大小和其内容。

C++程序设计模式

构造函数语义学

Constructor

对于一个class,若没有任何 user-declared constructor,那么会有一个default constructor被implicitly声明出来,这个声明通常是trivial(无能的,在STL中会采用直接内存操作的方式初始化)的,但在以下四种情况,是non-trivial的。

  • 带有Default Constructor的Member Class Object时,编译器声明的constructor会调用member class object的default constructor。这种情况下,即使有user-declared constructor,编译器也会按照Member Class Object定义的顺序补充调用他们的默认构造函数。
  • 带有Default Constructor的Base Class,derived class A需要合成一个constructor来调用父类的constructor,因此也是non-trival的,如此之后再继承该class A的子类,将把合成的A的constructor当作是显示声明的。
    • 此外即使A有user-declared的constructor,编译器也会扩充他们的每一个,按照顺序调用父类的default constructor。
    • 和第一种情况类似,Member Class Object的default constructor也会被扩充进来
  • 带有或者继承virtual function的class,因为需要给对象赋virtual function的地址;
  • 带有一个virtual base class的class,因为需要给对象赋virtual class对象的地址。

Copy Constructor

有三种情况,会以一个object的内容作为另一个class object的初值,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class X {...};
// 第一种情况,等号赋值
X x; // 由default constructor构造而来
X xx=x; // 显式的以一个object的内容作为另一个class object的初值,(注意这里是初始化,用到的仍是拷贝构造函数)

// 第二种情况,当作参数传入
extern void foo(X x);
void bar() {
X xx;
foo(xx); // 以xx作为foo()第一个参数的初值
}

// 第三种情况,当作返回值返回
X foo_bar(){
X *xx = new X();
return *xx;
}

Copy Constructor的逻辑是把每一个内建的或者派生的data member(例如一个指针或者数组)的值,从一个objec拷贝到另一个object中;对于其中的member class object,会采用递归的方式进行memberwise initialization

若没有显示的Copy Constructor声明,就会有Implicitly Copy Constructor被声明或者定义出来,他们是不是nontrivial的,会根据他们是否具有bitwise copy semiotics来判断。不遵照bitwise copy semiotics的情况

  • class中member objects中有声明copy constructor的情况(显式声明或者被编译器合成)

  • class继承自一个base class而后者存在一个copy constructor时

  • 当class 声明了一个或者多个virtual functions时,由于可能会存在类型的在继承树上的变化,所以需要重新设定virtual table的指针

    • 例如

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      class ZooAnimal{
      public:
      ZooAnimal();
      virtual ~ZooAnimal();
      virtual void animate();
      virtual void draw();
      }
      class Bear : public ZooAnimal{
      public:
      Bear();
      void animate();
      void draw();
      virtual void dance();
      }
      Bear beer;
      ZooAnimal a = beer; // 会发生切割行为,逐位复制的方式将会造成vptr错误
  • 当class 派生自一个继承串链,其中有一个或多个virtual base classes时

成员初始化列表(Member Initialization List)