复制控制

  复制构造函数赋值操作符析构函数总称为复制控制。编译器自动实现这些操作,但类也可以定义自己的版本。

  实现复制控制操作最困难的部分,往往在于识别何时需要覆盖默认版本。有一种特别常见的情况需要类定义自己的复制控制成员:类具有指针成员。

一、复制构造函数

  特点:只有单个形参;该形参是对本类型对象的引用(const T&)。

  复制构造函数可以用于:

  1. 根据另一个同类型的对象显式或隐式地初始化一个对象。

  2. 复制一个对象,将它作为实参传给一个函数。

  3. 从函数返回时复制一个对象。

  4. 初始化顺序容器中的元素。

  5. 根据元素初始化式列表初始化数组元素。

1.1、初始化:复制初始化和直接初始化

  int i(1024);      //direct initialization.

      int a = 1024;   //copy initialization.

  两者之间的不同:

  直接初始化直接调用与实参匹配的构造函数;复制初始化总是调用复制构造函数。复制初始化首先使用指定构造函数创建一个临时对象,然后用复制构造函数将那个临时对象复制到正在创建的对象:

  string null_book = "aaaaaaaaaa";           //copy initialization

  string dot(10, '.');                               //direct initialization

  string empty_copy = string();               //copy

  string empty_direct;                             //direct

1.2、形参与返回值

  正如我们所知,当形参为非饮用类型的时候,将复制实参的值。类似地,以非引用类型作为返回值时,将返回return语句中的副本。

  当形参或返回值为类类型时,由复制构造函数进行复制。当形参或返回值为类型引用时,不能复制。如:

      //copy constructor used to copy the return value.

      //parameters are references, so they aren't copied.

  string make(size_t, const string&, const string&);

1.3、合成的复制构造函数

  如果我们没有定义复制构造函数,编译器就会为我们合成一个。

  与合成的默认构造函数不同,即使我们定义了其他构造函数,也会合成复制构造函数。合成复制构造函数的行为是:执行逐个成员(非static 成员)初始化,将对新对象初始化为原对象的副本

  例如:

class Sales_item {
private:
    str::string isbn;
    int sold;
    double revenue;
}

合成复制构造函数如下:

Sales_item::Sales_item(const Sales_item&obj)
{
    isbn(obj.isbn);            //uses string copy construtor
    sold(obj.sold);
    revenue(obj.revenue);
}

二、禁止复制

  有的类需要完全禁止复制。例如:iostream类。

  如果复制构造函数是private的,将不会允许用户代码复制该类类型的对象,编译器将拒绝任何进行复制的尝试。

  然而,友元和成员仍可以进行复制。如果想要连友元和成员中的复制也禁止,就可以声明一个private复制构造函数但不对其定义

这是因为:声明而不定义成员函数是合法的,但是,使用未定义的成员的任何尝试将导致链接失败。

原文地址:https://www.cnblogs.com/wiessharling/p/3346112.html