编译器何时生成默认构造函数?
编译器生成的构造函数只适用于编译器的正确性,类内的数据初始化不由编译器负责!
- 如果一个class内部含有一个成员对象,并且这个对象有默认构造函数,那么编译器就会为这个class生成默认构造函数。
- 此class继承自一个含有默认构造函数的基类。
- 带有virtual function的Class或者继承了一个含有virtual fuction的父类。
- 使用了虚继承的类。
存在两个误解: - 任何class如果没有定义默认构造,编译器会生成。(错,编译器只会在需要的时候生成)
- 编译器生成的默认构造会明确初始化。(错,编译器不会初始化成员变量,这是程序设计者的活!)
拷贝构造函数
何时会用到拷贝构造?
- 明确初始化
1
2
3class X{};
X xx;
X xxx = xx; // 拷贝构造- 函数值传递
1
2X 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
24class 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编译器什么时候为我们生成拷贝构造?
决定一个拷贝构造是否被合成取决于class是否展现 bitwise copy semantics. 当展现了bitwise copy semantics,编译器不会合成默认拷贝构造。
什么时候不展现所谓逐位拷贝?
- class内部的member object有拷贝构造。
- class继承自一个具有拷贝构造的父类。
- class含有虚函数。
- class的继承链上有基类含有虚函数。
- 初始化列表
- 使用初始化列表可以避免一次不必要的赋值拷贝
- 记住初始化列表的初始化顺序是按照类内声明顺序就可以了,在初始化列表里如果某变量初始化依赖其他变量,在定义的时候记得调整先后顺序。