前言
即使我们写下1
class Empty{};
这样的空类,它本质上也不是空的,而是类似于:1
2
3
4
5
6
7class Empty{
public:
Empty(){}
Empty(const Empty& rhs) {}
~Empty() {}
Empty& operator=(const Empty& rhs) {}
}
在我们没有写的情况下,编译器会自动地生成default构造函数,copy构造函数,copy assignment操作符和析构函数。
这些函数都是inline并且public的。只有在他们被调用时,编译器才会创建它们。
自动生成的函数的性质与作用
default构造与default析构
default构造函数和析构主要是给编译器调用base clssses和non-static成员变量的构造函数和析构函数。这里需要注意的是,编译器生成的析构函数为non-virtual,除非this class 的base class自身声明有virtual析构函数。(此时thisclass的析构函数的virtualness源自base class)
copy构造函数与copy assignment操作符
至于copy构造函数与assignment操作符,编译器只是单纯地将来自源对象的non-static成员变量copy到目标对象。假设现有一个Widget Template,它允许你将一个string与一个T类型的数据发生关联:1
2
3
4
5
6
7
8
9
10template<typename T>
class Widget{
public:
Widget(const char* name,const T& name);
Widget(const string& name,const T& name);
...
private:
string thename;
T value;
}
因为已经声明了构造函数,所以编译器不会自动生成default构造函数,也就是说,一旦你创建了一个class,其对象需要一个参数才能构建,那你无需担心编译器会自动帮它生成无参构造函数。(关于无参构造函数的弊端可见More Effective 4)
Wideget既没有声明copy构造函数,也没有声明copy assignment操作符。因此编译器会自动生成它们,那么具体是如何实现的?1
2Widget<int> a("sth",5);
Widget b(a);//调用自动生成的copy构造函数
copy构造函数
编译器生成的copy构造函数会以a.thename
与a.value
为初值构造b.thename
与b.value
,因为string存在copy构造函数,因此它调用了string的copy构造函数生成了b.thename
,int属于内置类型,不存在copy构造函数,因此b.value
将会copya.value
的每一个bits来完成初始化。
copy assignment操作符
copy assignment操作符和copy构造函数略有不同,原因在于并非任何成员对象都可以被赋值(const成员变量,reference)。
在c++中,不允许reference改指向不同对象,也不允许const对象被赋值。因此,此时copy assignment无法完成,编译器拒绝生成此操作。也就是说,当class内含const成员与reference成员时,C++不会生成copy assignment操作符。
如果我们试图令内含reference成员或const成员的class支持copy assignment,那我们必须要自定义copy assignment操作符。
还有一种情况C++也不会生成copy assignment操作符,就是base class将copy assignment定义为private.原因很简单,如果编译器为derived class生成了copy assignment操作符,那它必定会试图调用base class的copy assignment操作符来操作base class的数据成员,可惜它没有这个权限来调用。
总结
编译器会自动生成某些函数,谨记它们的性质、作用、以及在什么情况下不会自动生成。