先让我们看看下面这个类:
class Empty {};
这个类在目前看来就是个空类。但是当我们做如下操作时,它们任然能够通过编译:
Empty e1;
Empty e2(e1);
e2 = e1;
上面的操作涉及到了构造函数、copy构造函数、copy assignment(operator =)还有一个不易被发现的析构函数。但是这些函数在Empty的定义中并没有发现,没被定义却能够使用,这是问什么能?是因为编译器在对Empty编译的时候默默地为我们做了一些工作,它在Empty中添加了如下所示的一些代码:
class Empty{
pulic:
inline Empty() {...}
inline Empty(const Empty& rhs) {... }
inline ~Empty() {...}
inline Empty& oprator=(const Empty& rhs) {...}
};
是的,编译器可以为我们暗自添加构造函数、copy构造函数、copy assignment操作符和析构函数,并且所有这些函数都是public inline。同时还需说明的是,这些函数被需要时,才会被编译器创建出来,并且产生的析构函数是non-virtual的,除非这个class的base class自身声明有virtual析构函数。
我们再来看看,究竟这些函数都做了些什么:
1、defualt构造函数和析构函数主要是给编译器一个地方来放置“藏身幕后”的代码,像是调用base class和non-static成员变量的构造函数和析构函数。
2、copy构造函数和copy assignment操作符,只是单纯地将来源对象的每个non-static成员变量拷贝到目标对象。
不过即便是它们被需要的时候,编译器也并不是一定会生成这些函数。如果在类的定义中已经存在一个构造函数,则编译器并不会无谓的为你添加一个defualt构造函数。而要产生copy assignment操作符,只有当产生出的代码合法且有适当机会证明它有意,即它需符合两个条件:该类中不含有reference成员和const成员,二者缺一不可。因为copy assignment其实也是调用类中成员变量的copy assignment进行copy操作。但是C++并不允许让reference改指向不同对象,同理也不允许修改const常量。因此当类中含有reference成员或const成员时,产生的代码是不合法的,所以不会产生copy assignment操作符。
有的时候我们可能并不希望用户使用copy构造或copy assignment操作符复制对象,但是编译器却勤恳的为我们生成了这些函数。怎么样才能让用户不能使用它们呢?方法就是把它声明为private,然后不去实现它。Singleton的实现就需要用到这样的手法。比如不想让用户使用Empty的copy构造函数和copy assignment操作符,代码如下:
class Empty{
public:
...
private:
Empty(const Empty&);
Empty& operator=(const Empty&);
....
};
---- 本文根据《Effective C++》条款5中的讲解写成