1、显式构造函数
复制构造函数是一种特殊构造函数,具有单个形参,该形参(常用 const 修饰)是对该类类型的引用。当定义一个新对象并用一个同类型的对象对它进行初始化时,将显式使用复制构造函数。当将该类型的对象传递给函数或函数返回该类型的对象时,将隐式使用复制构造函数。
编译器自动执行类中非static数据成员的析构函数。
2、赋值操作符可以通过指定不同类型的右操作数而重载。
3、有一种特别常见的情况需要自己定义的复制控制成员的:类具有指针成员。
4、C++支持两种初始化形式:直接初始化和复制初始化。复制初始化使用=,而直接初始化将初始化放在圆括号中。
当用于类类型对象时,初始化的复制形式和直接形式有所不同:直接初始化直接调用与实参匹配的构造函数,复制初始化总是调用复制构造函数。复制初始化首先使用指定构造函数创建一个临时对象,然后用复制构造函数将那个临时对象复制到正在创建的对象:
示例
string null_book = "00000"; //拷贝构造函数
string dotc(10, '.'); //直接初始化
string empty_copy = string(); //拷贝构造函数
string empty_direct; //直接初始化
5、以非引用类型作为返回值时,将返回return语句中的值的副本。
6、合成的复制构造函数
如果我们没有定义复制构造函数,编译器就会为我们合成一个。合成复制构造函数的行为是,执行逐个成员初始化,将新对象初始化为原对象的副本。
所谓“逐个成员”,指的是编译器将现在对象的每个非 static 成员,依次复制到正创建的对象。只有一个例外,每个成员的类型决定了复制该成员的含义。合成复制构造函数直接复制内置类型成员的值,类类型成员使用该类的复制构造函数进行复制。数组成员的复制是个例外。虽然一般不能复制数组,但如果一个类具有数组成员,则合成复制构造函数将复制数组。复制数组时合成复制构造函数将复制数组的每一个元素。
7、大多数类应定义复制构造函数和默认构造函数。不允许复制的类对象只能作为引用传递给函数或从函数返回,它们也不能用作容器的元素。只有不存在其他构造函数时才合成默认构造函数。
8、内置类型的赋值运算返回对左操作数的引用。
示例
class Sales_item
{
public:
Sales_item& operator=(const Sales_item&rhs)
{
isbn = rhs.isbn;
units_sold = rhs.units_sold;
revenue = rhs.revenue;
return *this; //返回左操作数的引用
}
};
9、合成赋值操作符与合成复制构造函数的操作类似。它会执行逐个成员赋值:右操作数对象的每个成员赋值给左操作数对象的对应成员。除数组之外,每个成员用所属类型的常规方式进行赋值。对于数组,给每个数组元素赋值。
10、析构函数
当对象的引用或指针超出作用域时,不会运行析构函数。只有删除指向动态分配对象的指针或实际对象(不是对象的引用)超出作用域时,才会运行析构函数。
如果类需要析构函数,则它也需要赋值操作和复制构造函数,这是一个有用的经验法则(通常称为三法则)。
11、与复制构造函数或赋值操作符不同,编译器总是会我们合成一个析构函数。合成析构函数按对象创建时的逆序撤销每个非static成员。合成析构函数并不删除指针成员所指向的对象。
12、析构函数没有形参,不能重载。即使我们编写了自己的析构函数,合成析构函数仍然运行。(先运行自定义的,再运行合成的)
13、析构函数对撤销内置类型或指针类型的成员没有影响。赋值操作必须是类的成员并且必须返回对类对象的引用。
关于复制构造函数中涉及的深拷贝,浅拷贝,及与赋值操作的异同,可以参见下列文章。
参考
[1] http://blog.163.com/zhoumhan_0351/blog/static/3995422720100250413207/
[2] http://blog.163.com/zhoumhan_0351/blog/static/39954227201032845132592/
[3] http://blog.163.com/zhoumhan_0351/blog/static/399542272010318112048522/
[4] http://blog.163.com/zhoumhan_0351/blog/static/39954227201032092854732/
[5] http://blog.163.com/zhoumhan_0351/blog/static/3995422720100284731826/
[6] http://blog.163.com/zhoumhan_0351/blog/static/39954227201012465955824/