C++ 复制控制之复制构造函数
7月26日更新:
过了这么长的时间回过头来看,发现文章中有几个点说错(用红字标出):
- 构造函数不是只有唯一一个参数,它也可以是多参数形式,其第二参数及后继以一个默认值供应。
 - 不是没有声明复制控制函数时编译器就一定会帮类声明,需要满足一定的条件。
 
《《=========================================================================》》
C++类用三个特殊的成员函数:复制构造函数、赋值操作符和析构函数 来决定类对象之间的初始化或赋值时发生什么。所谓的“复制控制”即通过这三个成员函数控制对象复制的过程。本篇文章将介绍复制构造函数。
- 复制构造函数
 
复制构造函数是什么
复制构造函数首先是一个构造函数,它同所有其他的构造函数一样与类同名,没有返回值。它有一个唯一的参数(错误),是该类类型的引用(一般将它声明为const,源于用于赋值的对象一般不用改变它本身的值)。于是复制构造函数的原型为:
class BOOK
{
public:
BOOK(const BOOK& rhs); //构造函数一
BOOK(string &name,float price = ):_bookName(name),_price(price){}; //构造函数二
BOOK():_price(),_bookName(""){}; //构造函数三 private:
float _price ;
string _bookName;
//....
};
什么时候被调用
复制构造函数在需要复制类对象的时候被调用,这些调用情况可以总结为:
- 根据一个同类型的对象显示或隐式地初始化一个对象。
 
当定义一个新对象并用一个同类型的对象对它进行初始化的时候,将显式使用复制构造函数,如:
BOOK book1;
BOOK book2(book1);
当将该类型的对象传递给函数或从函数返回该类型的对象时,将隐式地调用复制构造函数。
- 作为值传递的实参传递给一个函数。
 - 函数返回时复制一个对象。
 - 初始化顺序容器中的元素。
 
如:
vector<string> svec();
编译器首先调用string类默认构造函数创建一个临时值,再用复制构造函数将临时值复制到每一个元素。
- 根据元素初始化列表初始化数组元素。
 
如:
BOOK books[]={
  string("book1"),
  string("book2"),
  string("book3"),
  BOOK()
};
book数组的前三个元素将调用构造函数二进行隐式类型转换(C++隐式类型转换),然后调用复制构造函数进行数组元素的复制。如果类禁止隐式类型转换(构造函数使用了explicit声明),或希望不指定实参或多个实参,需要使用完整的构造函数语法,如数组最后一个元素的初始化。
如果没有为类声明复制构造函数会怎样
如果你没有声明一个复制构造函数,那么编译器会给声明一个。实际上,如果你自己没有声明,编译器会为类声明一个复制构造函数 ,一个赋值操作符以及一个析构函数,此外如果你没有声明任何构造函数的话,编译器也会为你声明一个合成默认构造函数。(错误)所有这些编译器自动生成的类成员函数皆为pubilc 且 inline。(这部分内容可以参考《Effective C++》条款05)编译器创建的复制构造函数单纯地将来源对象的每一个非static成员拷贝到目标对象,这在很多时候是不能满足类需求的,特别是类中含有指针时,这时候就需要我们自己来写复制控制的三个特殊成员函数了。
编译器合成的复制构造函数做了什么
合成复制构造函数的行为是:对每一个非static成员进行逐个成员初始化。成员类型不同,初始化方式不一样:
内置类型(如int):直接复制值。
类类型:调用该类的复制构造函数进行复制。
数组:这个比较特殊,因为我们知道一般不能复制数组,但在类中,复制数组时合成复制构造函数将复制数组的每一个值。
另外,合成复制构造函数对类数据成员的初始化都是放在构造函数初始化列表中进行的。
禁止复制
如果我们想禁止某个类的复制行为,我们当然不会想去定义一个复制构造函数,然而编译器却会自动为我们定义一个,那么到底该如何阻止一个类的复制行为呢?
我们可以将复制构造函数定义为private,不允许用户代码复制该类类型的对象,若进行复制将在编译时发生错误。然而类的友元和成员仍可以进行复制,解决办法是我们可以声明一个private复制构造函数却不进行定义,类成员或友元进行复制尝试时,将在程序运行时发生错误。
总结:为驳回编译器自动提供的机能,可将相应的成员函数声明为private并且不予实现。(具体可参考《Effective C++》条款06 若不想使用编译器自动生成的函数,就该明确拒绝)
C++ 复制控制之复制构造函数的更多相关文章
- C++复制控制:拷贝构造函数
		
一.拷贝构造函数是一种特殊构造函数,具有单个形参,该形参(常用const修饰)是对该类类型的引用.与默认构造函数一样 ,拷贝构造函数可由编译器隐式调用.拷贝构造函数应用的场合为: (1)根据另一个同类 ...
 - C++继承与构造函数、复制控制
		
每个派生类对象由派生类中定义的(非static)成员加上一个或多个基类子对象构成,因此,当构造.复制.赋值和撤销派生类型对象时,也会构造.复制.赋值和撤销这些基类子对象. 构造函数和复制控制成员不能继 ...
 - C++ Primer 学习笔记_67_面向对象编程 --转换与继承、复制控制与继承
		
面向对象编程 --转换与继承.复制控制与继承 I.转换与继承 引言: 由于每一个派生类对象都包括一个基类部分,因此能够像使用基类对象一样在派生类对象上执行操作. 对于指针/引用,能够将派生类对象的指针 ...
 - C++ Primer 随笔 Chapter 13 复制控制
		
1.复制控制包含的内容:复制构造函数.赋值操作符.析构函数 2.复制构造函数: a. 定义:只有单个形参,而且该形参是对本类类型的引用,这样的构造函数被成为复制构造函数 b. 适用情况: (1)根据一 ...
 - C++Primer笔记之复制控制
		
复制控制这一节需要注意的地方不多,主要有以下几点: 1.定义自己的复制构造函数 什么时候需要定义自己的复制构造函数,而不用系统提供的,主要遵循以下的经验说明: 某些类必须对复制对象时发生的事情加以控制 ...
 - C++之复制控制
		
只有单个形参,而且该形参是对本类类型对象的引用(常用const修饰),这样的构造函数叫做复制构造函数(有时也称为拷贝构造函数),例如: class Person{ public: Person();/ ...
 - 稍微深入点理解C++复制控制【转】
		
通过一个实例稍微深入理解C++复制控制过程,参考资料<C++ primer>,介绍点基本知识: 1.在C++中类通过特殊的成员函数:复制构造函数.赋值操作符和析构函数来控制复制.赋值和撤销 ...
 - C++拾遗(六)——复制控制
		
年前忙了几天,到现在才算是有空休息下来.先祝大家新年快乐,心想事成:)我也会发笑脸o.o 这篇博文主要介绍定义一个类型的对象时的复制控制方式,这部分内容之前有一定的了解但又浅尝辄止,始终感觉没能找到要 ...
 - C++ 类的复制控制
		
写了又删,删了又写,才发现这一章节不好描述. 那就假定个前提吧,假定已经知道: ① C++的类有构造函数. ② 如果不提供任何构造函数,那编译器会生成默认的无参构造函数--默认构造函数只会进行成员变量 ...
 
随机推荐
- HTML 学习笔记 CSS样式(链接)
			
我们能够以不同的方法为链接设置样式. 设置链接的样式 能够设置链接样式的 CSS 属性有很多种(例如 color, font-family, background 等等).链接的特殊性在于能够根据它们 ...
 - memcache 的内存管理介绍和 php实现memcache一致性哈希分布式算法
			
1 网络IO模型 安装memcached需要先安装libevent Memcached是多线程,非阻塞IO复用的网络模型,分为监听主线程和worker子线程,监听线程监听网络连接,接受请求后,将连接描 ...
 - 资料,来自HTML5前端开发学习⑤群
			
resource HTML5+CSS3视频教程:http://pan.baidu.com/s/1hsyOjze 密码:c3uw JavaScript视频教程:链接:http://pan.baidu.c ...
 - sublime和python--path
			
配置Sublime Text 2 的Python运行环境 (2013-09-11 11:36:17) 转载▼ 标签: python 分类: 科技相关 Sublime Text 2作为一款轻量级 ...
 - 039医疗项目-模块四:采购单模块—采购单的创建-----------Dao层,service层,Acion层
			
我们根据数据库里面的表格:生成对应的Mapper接口文件和...Mapperxml文件: YYCGD:采购单模板表. YYCGD2014:采购单动态生成表,由存储过程生成. YYCGDMX:采购单明细 ...
 - 基于JSch的Sftp工具类
			
本Sftp工具类的API如下所示. 1)构造方法摘要 Sftp(String host, int port, int timeout, String username, String password ...
 - linux传输大文件
			
http://dreamway.blog.51cto.com/1281816/1151886 linux传输大文件
 - mac下环境变量、maven3.1.1 及 jdk1.7.0.45配置
			
一.设置环境变量 1.打开终端,输入 cd ~ 2.输入 touch .bash_profile (如果该文件不存在,将创建一个空文件) 3.输入 open .bash_profile (调用记事本编 ...
 - Webwork 学习之路【04】Configuration 详解
			
Webwork做为经典的Web MVC 框架,个人觉得源码中配置文件这部分代码的实现十分考究. 支持自定义自己的配置文件.自定义配置文件读取类.自定义国际化支持. 可以作为参考,单独引入到其他项目中, ...
 - lecture8-RNN的训练方法之二三
			
HInton第8课,之所以说之二三,是因为训练RNN的四种方法之一:长短时记忆在lecture7中介绍过了,这里介绍的是第二和第三种方法:HF优化和Echo (这个字觉得翻译成回声是不是欠妥,所以保留 ...