对于一个empty class(空类),编译器就会为它声明(编译器版本的)一个copy构造函数,一个copy assignment操作符和一个析构函数,此外你没有声明任何构造函数,编译器也会为你声明一个default构造函数。
如下所示:
//当你写下如下的代码:
class Empty{};
//就像如下的代码一样:
class Empty
{
public:
Empty{...}; //default构造函数
Empty(const Empty& rhs){...} //copy构造函数
~Empty{...}; //析构函数,是否为虚见稍后说明
Empty& operator = (const Empty& rhs) {...};//copy assignment操作符
};
唯有当这些函数被需要(调用),它们才会被编译器创建出来。
对于这几个函数而言作用:default构造和析构函数主要给编译器一个地方来放置“藏身幕后”的代码,像是调用base classes和non-static成员变量的构造函数和析构函数。至于copy构造函数和copy assignment操作符,编译器创建的版本只是单纯的将源对象的每一个non-static成员变量拷贝到目标对象。
编译器生成的copy assignment操作符,其行为基本上和copy构造函数如出一辙,但一般而言只有当生成的代码合法且有适当机会证明他有意义,其表现才会如我们所说的。万一条件不符合,编译器会拒绝为class生成operator=。
特殊的情况,如下NamedObject定义如下,nameValue是个reference to string,objectValue是个const T:
template<class T>
class NamedOjbect
{
public:
NamedOjbect(std::string& name,const T& value);
...
private:
std::string& nameValue;
const T objectValue;
};
std::string newDog("Persephone");
std::string oldDog("Satch");
NamedOjbect<int> p(newDog,2);
NamedOjbect<int> s(oldDog,36);
p = s;//现在p的成员变量该发生什么事
赋值之前,不论p.nameValue和s.nameValue都是指向string对象(不是同一个),赋值动作该如何影响p.nameValue?因为C++不允许“让一个reference指向不同对象”。对面const成员也是如此,更改const成员时不合法的。
面对这问题,C++编译器拒绝为其合成copy assignment,你必须自己定义copy assignment。最后还有一种特殊情况:如果某个base classes将copy assignment操作符声明为private,编译器也会拒绝为其derived classes生成一个copy assignment操作符,毕竟编译器为derived classes所生成的copy assignment操作符想象中可以处理base class成分。
总结
- 编译器可以暗自为class创建default构造函数、copy构造函数、copy assignment操作符,以及析构函数。