C++对象模型:构造函数

编译器何时生成默认构造函数?

编译器生成的构造函数只适用于编译器的正确性,类内的数据初始化不由编译器负责!

  1. 如果一个class内部含有一个成员对象,并且这个对象有默认构造函数,那么编译器就会为这个class生成默认构造函数。
  2. 此class继承自一个含有默认构造函数的基类。
  3. 带有virtual function的Class或者继承了一个含有virtual fuction的父类。
  4. 使用了虚继承的类。
    存在两个误解:
  5. 任何class如果没有定义默认构造,编译器会生成。(错,编译器只会在需要的时候生成)
  6. 编译器生成的默认构造会明确初始化。(错,编译器不会初始化成员变量,这是程序设计者的活!)

拷贝构造函数

  1. 何时会用到拷贝构造?

    • 明确初始化
    1
    2
    3
    class X{};
    X xx;
    X xxx = xx; // 拷贝构造
    • 函数值传递
    1
    2
    X xx;
    func(xx); // 函数内部拷贝副本
    • 函数内对象返回(此处在g++7.5版本中没有调用拷贝构造,直接返回了对象,属于编译优化)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    class X{
    public:
    X(){}
    X(const X& x){
    i = x.i;
    cout << "copy" ;
    }
    int i = 0;
    };

    X func(){
    X xx;
    xx.i = 10;
    cout << (int *)&xx << endl;
    return xx;
    }

    int main(){
    X x = func();
    cout << (int *)&x;
    return 0;
    }
    //0x7ffffe3b1284
    //0x7ffffe3b1284
  2. 编译器什么时候为我们生成拷贝构造?
    决定一个拷贝构造是否被合成取决于class是否展现 bitwise copy semantics. 当展现了bitwise copy semantics,编译器不会合成默认拷贝构造。

  • 什么时候不展现所谓逐位拷贝?

    • class内部的member object有拷贝构造。
    • class继承自一个具有拷贝构造的父类。
    • class含有虚函数。
    • class的继承链上有基类含有虚函数。
  1. 初始化列表
  • 使用初始化列表可以避免一次不必要的赋值拷贝
  • 记住初始化列表的初始化顺序是按照类内声明顺序就可以了,在初始化列表里如果某变量初始化依赖其他变量,在定义的时候记得调整先后顺序。