如果您没有定义这四个方法(C++11 中的六个),编译器将为您生成它们:
- 默认构造函数
- 复制构造函数
- 赋值运算符
- 析构函数
- 移动构造函数 (C++11)
- 移动赋值 (C++11)
如果你想知道为什么?
这是为了保持与 C 的向后兼容性(因为 C 结构可以使用 = 和在声明中复制)。但它也使编写简单的类更容易。有些人会争辩说,由于“浅拷贝问题”,它增加了问题。我反对这一点的论点是,你不应该有一个拥有 RAW 指针的类。通过使用适当的智能指针,问题就消失了。
默认构造函数(如果没有定义其他构造函数)
编译器生成的默认构造函数会调用基类的默认构造函数,然后是每个成员的默认构造函数(按照它们被声明的顺序)
析构函数(如果没有定义析构函数)
以相反的声明顺序调用每个成员的析构函数。然后调用基类的析构函数。
复制构造函数(如果没有定义复制构造函数)
调用传递 src 对象的基类复制构造函数。然后使用 src 对象成员作为要复制的值调用每个成员的复制构造函数。
赋值运算符
调用传递 src 对象的基类赋值运算符。然后使用 src 对象作为要复制的值对每个成员调用赋值运算符。
移动构造函数(如果没有定义移动构造函数)
调用传递 src 对象的基类移动构造函数。然后使用 src 对象成员作为要移动的值调用每个成员的移动构造函数。
移动赋值运算符
调用传递 src 对象的基类移动赋值运算符。然后使用 src 对象作为要复制的值对每个成员调用移动赋值运算符。
如果你这样定义一个类:
struct some_struct: public some_base
{
std::string str1;
int a;
float b;
char* c;
std::string str2;
};
编译器将构建的是:
struct some_struct: public some_base
{
std::string str1;
int a;
float b;
char* c;
std::string str2;
// Conceptually two different versions of the default constructor are built
// One is for value-initialization the other for zero-initialization
// The one used depends on how the object is declared.
// some_struct* a = new some_struct; // value-initialized
// some_struct* b = new some_struct(); // zero-initialized
// some_struct c; // value-initialized
// some_struct d = some_struct(); // zero-initialized
// Note: Just because there are conceptually two constructors does not mean
// there are actually two built.
// value-initialize version
some_struct()
: some_base() // value-initialize base (if compiler generated)
, str1() // has a normal constructor so just call it
// PODS not initialized
, str2()
{}
// zero-initialize version
some_struct()
: some_base() // zero-initialize base (if compiler generated)
, str1() // has a normal constructor so just call it.
, a(0)
, b(0)
, c(0) // 0 is NULL
, str2()
// Initialize all padding to zero
{}
some_struct(some_struct const& copy)
: some_base(copy)
, str1(copy.str1)
, a(copy.a)
, b(copy.b)
, c(copy.c)
, str2(copy.str2)
{}
some_struct& operator=(some_struct const& copy)
{
some_base::operator=(copy);
str1 = copy.str1;
a = copy.a;
b = copy.b;
c = copy.c;
str2 = copy.str2;
return *this;
}
~some_struct()
{}
// Note the below is pseudo code
// Also note member destruction happens after user code.
// In the compiler generated version the user code is empty
: ~str2()
// PODs don't have destructor
, ~str1()
, ~some_base();
// End of destructor here.
// In C++11 we also have Move constructor and move assignment.
some_struct(some_struct&& copy)
// ^^^^ Notice the double &&
: some_base(std::move(copy))
, str1(std::move(copy.str1))
, a(std::move(copy.a))
, b(std::move(copy.b))
, c(std::move(copy.c))
, str2(std::move(copy.str2))
{}
some_struct& operator=(some_struct&& copy)
// ^^^^ Notice the double &&
{
some_base::operator=(std::move(copy));
str1 = std::move(copy.str1);
a = std::move(copy.a);
b = std::move(copy.b);
c = std::move(copy.c);
str2 = std::move(copy.str2);
return *this;
}
};