6.了解C++自动生成与调用的函数

前言

即使我们写下

1
class Empty{};

这样的空类,它本质上也不是空的,而是类似于:
1
2
3
4
5
6
7
class 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
10
template<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
2
Widget<int> a("sth",5);
Widget b(a);//调用自动生成的copy构造函数

copy构造函数

编译器生成的copy构造函数会以a.thenamea.value为初值构造b.thenameb.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的数据成员,可惜它没有这个权限来调用。

总结

编译器会自动生成某些函数,谨记它们的性质、作用、以及在什么情况下不会自动生成。