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


一、关于对象

关于菱形继承对象的内存分布,可以查看C++菱形继承内存布局分析了解。

二、构造函数语义学

  1. 四种情况下,编译器会为未声明 contructor 的 class 合成一个 default constructor。

    • 带有 Default Constructor 的 Member Class Object

      如果一个 class 没有任何的 constructor, 但是它含有一个拥有 default constructor 的 member object,那么这个 class 的 implicit default constructor 就是 nontrivial,编译器需要为此 class 合成一个 default constructor。此 class 的 default constructor 会调用每个 member object 的 default constructor。

    • 带有 Default Constructor 的 Base Class

      类似的道理,一个没有任何 constructor 的 class 派生自一个带有 default constructor 的 base class,这个 derived class 的 default constructor 会被视为 nontrivial,并需要被合成出来。它将调用上一层 base class 的 default constructor (根据它们的声明次序)。对这个 derived class 来说,合成出来的 constructor 和一个明确提供的 default constructor 一样。

    • 带有一个Virtual Function 的 Class

      另外两种情况,也需要合成出 default constructor:

      1. class 声明(或继承)一个 virtual function。
      2. class 派生自一个继承串链,其中有一个或更多的 virtual base classes。
    • 带有一个 Virtual Base Class 的 Class

      这些合成的 constructor 叫 implicit nontrivial default constructor。不满足上面四种情况且没有声明任何 constructor 的 class, 他们的 constructor 叫 implicit trivial default constructor,编译不会为这些 class 合成 constructor。

      在合成的 default constructor 中,只有 base class subojectsmember class objects 会被初始化。所有其他的 nonstatic data member,如整数、整数指针、整数数组等都不会被初始化。

  2. 和 default constructor 一样,如果 class 没有声明一个 copy constructor,编译器就会隐式的声明(implicitly declared)或隐式的定义(implicitly defined)一个。copy constructor 也分为 trivial 和 nontrivial 两种。只有 nontrivial 的实体才会被合成于程序中。决定一个 copy constructor 是否为 trivial 的标准在于 class 是否展现出所谓的”bitwise copy semantic”。

  3. 四种情况下,class 不展现出”bitwise copy semantic”。

    • 当 class 内含一个 member object 而后者的 class 声明中有一个 copy constructor。

    • 当 class 继承自一个 base class 而后者存在有一个 copy constructor 时(不能是被明确声明或是被合成而得)。

    • 当 class 声明一个或多个 virtual functions 时。

    • 当 class 派生自一个继承串链,其中有一个或多个 virtual base classes 时。

三、Data 语意学

  1. 上古时期,下面代码中,类A的成员函数返回的是全局x,而不是成员变量x。这个问题已经修复了,现在总数返回成员变量x。

    int x;
    
    struct A
    {
        int Func()
        {
            return x;
        }
        int x;
    };
  2. 下面的代码中,val_t的类型是使用全局的val_t的定义,即x,而不是类中声明的val_t,所以需注意。

    using val_t = int;
    
    struct A
    {
        void FuncA(val_t v)
        {
            printf("sizeof(val_t) = %d\n", sizeof(v)); // = sizeof(int) = 4
        }
        using val_t = char;
        void FuncB(val_t v)
        {
            printf("sizeof(val_t) = %d\n", sizeof(v)); // = sizeof(char) = 1
        }
    };
    
    int main(int argc, char** argv)
    {
        A a;
        a.FuncA(0);
        a.FuncB(0);
    
        return 0;
    }

    运行结果

    sizeof(val_t) = 4
    sizeof(val_t) = 1

四、Function 语意学

五、构造、解构、拷贝语意学

六、执行期语意学

七、站在对象模型的尖端


文章作者: Kiba Amor
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 Kiba Amor !
  目录