结论
编译器只在需要的时候合成编译器完成必要工作所需要的默认构造、拷贝构造、拷贝赋值函数
构造函数语义
一、合成的默认构造函数
- 合成时机:默认构造函数在被编译器需要的时候被合成;
- 功能:只执行编译器需要的行动;
- 具体说明
- 类中包含成员对象,且该成员对象的类有默认构造函数:编译器会合成一个默认构造函数,只执行必要的操作用来调用foo的默认构造,但是不会对str进行任何处理。
- 派生自带有默认构造函数的基类:
[例] 同上 - 带有虚函数的类:
编译器为了支持多态,会为每一个类安插一个虚表的指针,所以,会合成一个用于初始化虚函数表指针的默认构造;
若已经定义了构造函数,编译器会对现有的构造函数进行扩充,用于虚函数表的初始化。 - 带有虚基类的类
初始化虚基类的相关指针
- 额外说明:如果class A内含一个或一个以上的member class objects,那么class A的每一个constructor 必须调用每一个member classes 的 default constructor;编译期会扩张已存在的constructors,在其中安插一些代码,使得用户代码被执行之前,先调用必要的default constructors。
// 例
class Foo
{
public:
Foo();
...
};
class Bar
{
public:
Foo foo;
char* str;
inline Bar():foo()
{
//编译器合成版本
}
Bar(Param p):foo()/*编译器添加,按照类中声明顺序进行初始化*/
{
//显示默认构造/带参构造
}
};
二、拷贝构造函数
- 拷贝构造的三种情形
- 以一个对象直接构造另一个对象
- 函数参数
- 函数返回值
- 默认拷贝构造,逐成员初始化
- 位逐次拷贝语义(类似于memcpy)
- 以下几种情况会抑制逐比特拷贝语义:
- 内含成员对象,且声明了拷贝构造函数(编译器合成或者显式定义)
- 派生自声明了(合成或者自定义)拷贝构造函数的基类
- 含有虚函数或者虚基类
- 以下几种情况会抑制逐比特拷贝语义:
- 拷贝构造函数合成时机:类不具有逐比特拷贝语义
/// 拷贝函数调用
Foo foo2 = foo1;
void Fun(Foo foo);
Foo Fun(){Foo foo; return foo;}
/// 默认拷贝构造
class String
{
int len;
char* str;
};
class Person
{
int age;
String name;
String sex;
};
Person p1(10, "Li Hua", "男");
Person p2 = p1; // p2.age = p1.age; p2.name.len = p2.name.len; p2.name.str = p2.name.str; p2.sex.len = p1.sex.len; p2.sex.str = p1.sex.str;
三、对象赋值语义
- 内含成员对象,且声明了operator=()(编译器合成或者显式定义)
- 派生自声明了(合成或者自定义)operator=()的基类
- 含有虚函数或者虚基类
四、程序转化语义,拷贝构造的调用策略
1、显示初始化
class X
{
//...
};
X x0;
void Fun()
{
X x1(x0);
X x2 = x0;
X x3 = X(x0);
}
void Fun()
{
X x1;
X x2;
X x3;
x1.X::X(x0);
x2.X::X(x0);
x3.X::X(x0);
}
2、参数初始化
// 一种策略
void Fun(X x0)
{
//...
}
X xx;
Fun(xx);
// 转化
X _tmpx0;
_tmpx0.X::X(x0);
Fun(_tmpx0);
void Fun(X &x0);
3、返回值初始化
X Fun()
{
X xx;
//....
return xx;
}
// 一种策略
// 猜测,可能返回类对象的函数可以直接复制和这个有关系,见下
void Fun(X &_result)
{
X xx;
xx.X::X();
// 处理xx
_result.X::X(xx);
return;
}
X res;
Fun(res);
// 成员函数调用
Fun().some_memfun();
X _tmpx;
(Fun(_tmpx), _tmpx).some_memfun();
// 拷贝赋值函数调用
X x0;
(Fun(_tmpx), _tmpx).operator=(x0);
// 返回值优化
void Fun(X &_result)
{
//X xx;
//xx.X::X();
// 处理xx
_result.X::X();
// 直接处理_result
return;
}
默认构造函数示例
class TestA1
{
private:
int m_memInt;
char* m_memStr;
}
class TestB1
{
TestA1 m_memA;
}
class TestA2
{
private:
int m_memInt;
char* m_memStr;
public:
TestA1(){}
}
class TestB2
{
TestA2 m_memA;
}
class TestA3
{
private:
int m_memInt;
char* m_memStr;
public:
TestA3(int nInt, char* szStr){}
}
class TestB3
{
TestA3 m_memA;
}
拷贝构造函数示例
class TestA4
{
private:
int m_memInt;
char* m_memStr;
}
class TestB4
{
TestA4 m_memA;
}
class TestA5
{
private:
int m_memInt;
char* m_memStr;
public:
TestA5(const TestA5& rhs){}
}
class TestB5
{
TestA5 m_memA;
int m_memInt;
}
class TestB5Ex
{
TestA5 m_memA;
int m_memInt;
public:
TestB5Ex(const TestB5Ex& rhs){}
}
class TestA6
{
private:
int m_memInt;
char* m_memStr;
public:
TestA6(){
m_memInt = 0;
m_memStr = nullptr;
cout<<"无参构造"<<endl;
}
TestA6(const TestA5& rhs){
cout<<"拷贝构造"<<endl;
}
}
class TestB6
{
TestA6 m_memA;
int m_memInt;
}
class TestB6Ex
{
TestA6 m_memA;
int m_memInt;
public:
TestB6Ex(const TestB6Ex& rhs){}
}
int main(){
TestB6 b6_1;
TestB6 b6_2 = b6_1;
TestB6Ex b6e_1;
TestB6Ex b6e_2 = b6e_1;
}