1、拷贝构造函数是一种特殊构造函数,具备单个形参,该形参(经常使用const修饰)是对该类类型的引用。与默认构造函数同样 ,拷贝构造函数可由编译器隐式调用。拷贝构造函数应用的场合为:ios
(1)根据另外一个同类型的对象显式或隐式初始化一个对象。数组
(2)复制一个对象将它做为实参传给一个函数。函数
(3)从函数返回时复制一个对象。spa
(4)初始化顺序容器中的元素。指针
(5)根据元素初始化式列表初始化数组元素。code
下面分别对以上5点进行说明。对象
一、对象的定义式。blog
C++支持两种初始化形式:直接初始化和复制初始化。复制初始化使用“=”符号,而直接初始化将初始化式放在圆括号中。对于类类型对象,初始化的复制形式和直接形式有所不一样。ci
直接初始化直接调用与实参匹配的构造函数。复制初始化首先使用指定构造函数建立一个临时对象,而后用拷贝构造函数将那个临时对象复制到正在建立的对象。资源
string null_book = "9-999-99999-9"; // copy-initialization string dots(10, '.'); // direct-initialization string empty_copy = string(); // copy-initialization string empty_direct; // direct-initialization
说明:
(1)对于类类型对象,只有指定单个实参或显式建立一个临时对象用于复制时,才使用复制初始化。
(2)支持初始化的复制形式主要是为了与C的用法兼容。当状况许可时,能够容许编译器跳过复制构造函数直接建立对象,但编译器没有义务这样作。
(3)对于不支持复制的类型,或者使用explicit构造函数,不能进行复制初始化。例如:因为不能复制IO类型的对象,因此不能对那些类型的对象使用复制初始化。
ifstream file1("filename"); // ok: direct initialization ifstream file2 = "filename"; // error: copy constructor is private // This initialization is okay only if the Sales_item(const string&) constructor is not explicit Sales_item item = string("9-999-99999-9");
二、形参与返回值。
当形参为非引用类型时,将复制实参的值,以非引用类型做返回值时,将返回return语句中值的副本。于是,当形参或返回值为类类型时,由拷贝构造函数进行复制。
string make_plural(size_t, const string &, const string &);
这个函数隐式使用string拷贝构造函数返回值的副本,形参是const引用,不会复制。
三、初始化容器元素。
vector<string> vec(5);
使用了默认构造函数和拷贝构造函数。编译器首先使用string默认构造函数建立一个临时对象,而后使用拷贝构造函数将临时值复制到vec的每一个元素。
四、构造函数与数组元素。
当用花括号初始化列表来显式初始化类类型的数组,则使用复制初始化来初始化每一个元素。根据指定值建立适当类型元素,而后用拷贝构造函数将该值复制到相应元素。
Sales_item primer_eds[] = { string("0-201-16487-6"), string("0-201-54848-8"), string("0-201-82470-1"), Sales_item() };
当定义一个新对象并用一个同类型的对象对它初始化时,将显式使用拷贝构造函数。当将该类型的对象传递给函数或从函数返回该类型的对象时,将隐式使用拷贝构造函数。
2、合成的拷贝构造函数。
若是没有定义拷贝构造函数,编译器就会为咱们合成一个。与合成的默认构造函数不一样,即便咱们定义了其余构造函数,也会合成拷贝构造函数。合成拷贝构造函数的行为是,执行逐个成员初始化,将新对象初始化为原对象的副本。
说明:
(1)编译器将如今对象的每一个非static成员,依次复制到正建立的对象。每一个成员的类型决定了复制该成员的含义。
(2)合成拷贝构造函数直接复制内置类型成员的值,类类型成员使用该类的拷贝构造函数进行复制。
(3)数组成员的复制是个例外。虽然通常不能复制数组,但若是一个类具备数组成员,则合成复制构造函数将复制数组的每个元素。
Sales_item::Sales_item(const Sales_item &orig): isbn(orig.isbn), //使用string拷贝构造函数 units_sold(orig.units_sold), //直接复制orig.units_sold revenue(orig.revenue) //直接复制orig.revenue { }
3、定义本身的拷贝构造函数。
拷贝构造函数就是接受单个类类型引用形参(一般用const修饰)的构造函数。由于用于向函数传递对象和从函数返回对象,该构造函数通常不该设置为explicit,拷贝构造函数应将实参的成员复制到正在构造的对象。它与类同名,没有返回值,能够(并且应该)使用构造函数初始化列表初始化新建立对象的成员,能够在函数体中作任何其余必要工做。
说明:
(1)合成拷贝构造函数只完成必要的工做。只包含类类型成员或内置类型(但不是指针类型)成员的类,无须显式地定义拷贝构造函数,也能够复制。
(2)有些类必须定义复制构造函数对复制对象时发生的事情加以控制。例如:
1)类有一个数据成员是指针,或者有成员表示在构造函数中分配的其余资源
2)类在建立新对象时必须作一些特定工做。
4、禁止复制。
有些类须要彻底禁止复制,例如:iostream。如何禁止复制呢?省略拷贝构造函数这种作法不行,由于编译器将会帮咱们合成一个。为了防止复制,类必须显式声明其拷贝构造函数为private。
说明:
(1)若是拷贝构造函数是私有的,将不容许用户复制该类型对象。
(2)类的友元和成员仍能够进行复制,若是也想禁止它们,可声明一个私有的拷贝构造函数但不对其定义。声明而不定义是合法的,但使用未定义的成员将致使连接失败。
(3)经过声明不定义私有拷贝构造函数,可禁止任何复制类类型对象的尝试:用户尝试复制致使编译错误,成员函数和友元复制致使连接错误。
(4)若是定义了拷贝构造函数,也必须定义默认构造函数。不容许复制的类对象只能做为引用传递给函数或从函数返回,它们也不能做为容器元素,严重局限类的使用。