C++复制控制:拷贝构造函数
一、拷贝构造函数是一种特殊构造函数,具有单个形参,该形参(常用const修饰)是对该类类型的引用。与默认构造函数一样 ,拷贝构造函数可由编译器隐式调用。拷贝构造函数应用的场合为:
(1)根据另一个同类型的对象显式或隐式初始化一个对象。
(2)复制一个对象将它作为实参传给一个函数。
(3)从函数返回时复制一个对象。
(4)初始化顺序容器中的元素。
(5)根据元素初始化式列表初始化数组元素。
下面分别对以上5点进行说明。
1、对象的定义式。
C++支持两种初始化形式:直接初始化和复制初始化。复制初始化使用“=”符号,而直接初始化将初始化式放在圆括号中。对于类类型对象,初始化的复制形式和直接形式有所不同。
直接初始化直接调用与实参匹配的构造函数。复制初始化首先使用指定构造函数创建一个临时对象,然后用拷贝构造函数将那个临时对象复制到正在创建的对象。
string null_book = "9-999-99999-9"; // copy-initialization
string dots(, '.'); // 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");
2、形参与返回值。
当形参为非引用类型时,将复制实参的值,以非引用类型作返回值时,将返回return语句中值的副本。因而,当形参或返回值为类类型时,由拷贝构造函数进行复制。
string make_plural(size_t, const string &, const string &);
这个函数隐式使用string拷贝构造函数返回值的副本,形参是const引用,不会复制。
3、初始化容器元素。
vector<string> vec();
使用了默认构造函数和拷贝构造函数。编译器首先使用string默认构造函数创建一个临时对象,然后使用拷贝构造函数将临时值复制到vec的每个元素。
4、构造函数与数组元素。
当用花括号初始化列表来显式初始化类类型的数组,则使用复制初始化来初始化每个元素。根据指定值创建适当类型元素,然后用拷贝构造函数将该值复制到相应元素。
Sales_item primer_eds[] = { string("0-201-16487-6"),
string("0-201-54848-8"),
string("0-201-82470-1"),
Sales_item()
};
当定义一个新对象并用一个同类型的对象对它初始化时,将显式使用拷贝构造函数。当将该类型的对象传递给函数或从函数返回该类型的对象时,将隐式使用拷贝构造函数。
二、合成的拷贝构造函数。
如果没有定义拷贝构造函数,编译器就会为我们合成一个。与合成的默认构造函数不同,即使我们定义了其他构造函数,也会合成拷贝构造函数。合成拷贝构造函数的行为是,执行逐个成员初始化,将新对象初始化为原对象的副本。
说明:
(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
{ }
三、定义自己的拷贝构造函数。
拷贝构造函数就是接受单个类类型引用形参(通常用const修饰)的构造函数。因为用于向函数传递对象和从函数返回对象,该构造函数一般不应设置为explicit,拷贝构造函数应将实参的成员复制到正在构造的对象。它与类同名,没有返回值,可以(而且应该)使用构造函数初始化列表初始化新创建对象的成员,可以在函数体中做任何其他必要工作。
说明:
(1)合成拷贝构造函数只完成必要的工作。只包含类类型成员或内置类型(但不是指针类型)成员的类,无须显式地定义拷贝构造函数,也可以复制。
(2)有些类必须定义复制构造函数对复制对象时发生的事情加以控制。例如:
1)类有一个数据成员是指针,或者有成员表示在构造函数中分配的其他资源
2)类在创建新对象时必须做一些特定工作。
四、禁止复制。
有些类需要完全禁止复制,例如:iostream。如何禁止复制呢?省略拷贝构造函数这种做法不行,因为编译器将会帮我们合成一个。为了防止复制,类必须显式声明其拷贝构造函数为private。
说明:
(1)如果拷贝构造函数是私有的,将不允许用户复制该类型对象。
(2)类的友元和成员仍可以进行复制,如果也想禁止它们,可声明一个私有的拷贝构造函数但不对其定义。声明而不定义是合法的,但使用未定义的成员将导致链接失败。
(3)通过声明不定义私有拷贝构造函数,可禁止任何复制类类型对象的尝试:用户尝试复制导致编译错误,成员函数和友元复制导致链接错误。
(4)如果定义了拷贝构造函数,也必须定义默认构造函数。不允许复制的类对象只能作为引用传递给函数或从函数返回,它们也不能作为容器元素,严重局限类的使用。
C++复制控制:拷贝构造函数的更多相关文章
- 《挑战30天C++入门极限》C++类对象的复制-拷贝构造函数
C++类对象的复制-拷贝构造函数 在学习这一章内容前我们已经学习过了类的构造函数和析构函数的相关知识,对于普通类型的对象来说,他们之间的复制是很简单的,例如: int a = 10; int ...
- Effective C++ .12 复制对象-拷贝构造函数的编写
当我们自己编写拷贝构造函数时,编译器就不会为该类生成默认拷贝构造函数了,对于assignment operator也是如此. 1. 拷贝构造函数中记得调用父类的拷贝构造函数,或者相应复制过程 clas ...
- C++ 复制控制之复制构造函数
7月26日更新: 过了这么长的时间回过头来看,发现文章中有几个点说错(用红字标出): 构造函数不是只有唯一一个参数,它也可以是多参数形式,其第二参数及后继以一个默认值供应. 不是没有声明复制控制函数时 ...
- C++复制(拷贝)构造函数详解
本文转载自 http://blog.csdn.net/lwbeyond/article/details/6202256,在此感谢作者 CTemp B(A); //复制构造函数,C++风格的 ...
- C++构造函数详解(复制构造函数 也是 拷贝构造函数)
构造函数是干什么的 该类对象被创建时,编译系统对象分配内存空间,并自动调用该构造函数,由构造函数完成成员的初始化工作,故:构造函数的作用:初始化对象的数据成员. 构造函数的种类 1 class Com ...
- C++继承与构造函数、复制控制
每个派生类对象由派生类中定义的(非static)成员加上一个或多个基类子对象构成,因此,当构造.复制.赋值和撤销派生类型对象时,也会构造.复制.赋值和撤销这些基类子对象. 构造函数和复制控制成员不能继 ...
- C++类构造函数、拷贝构造函数、复制构造函数、复制构造函数、构造函数显示调用和隐式调用
一. 构造函数是干什么的 class Counter { public: // 类Counter的构造函数 // 特点:以类名作为函数名,无返回 ...
- C++ Primer 学习笔记_67_面向对象编程 --转换与继承、复制控制与继承
面向对象编程 --转换与继承.复制控制与继承 I.转换与继承 引言: 由于每一个派生类对象都包括一个基类部分,因此能够像使用基类对象一样在派生类对象上执行操作. 对于指针/引用,能够将派生类对象的指针 ...
- 你好,C++(34)有一只叫做多利的羊 6.2.4 拷贝构造函数
6.2.4 拷贝构造函数 在C++世界中,除了需要使用构造函数直接创建一个新的对象之外,有时还需要根据已经存在的某个对象创建它的一个副本,就像那只叫做多利的羊一样,我们希望根据一只羊创建出来另外一只 ...
随机推荐
- Java实现:服务端登录系统并跳转到系统内的指定页面(不调用浏览器)
Java实现:服务端登录系统并跳转到系统内的指定页面(不调用浏览器) 1,思路:根据爬虫思想: 2,代码: /** * ClassName:AuthFr * Function: TODO * Reas ...
- Git与TortoiseGit使用方法
下载这两个工具 Git地址:https://git-for-windows.github.io/ TortoiseGit地址:http://tortoisegit.org/ 点击 ...
- WCF使用安全证书验证消息加密
首先安装 服务端安全证书 代码如下: // 下面第一行是安装证书,第二行是将证书列入信任 makecert.exe -sr LocalMachine -ss MY -a sha1 -n CN=lo ...
- 【ES6】改变 JS 内置行为的代理与反射
代理(Proxy)可以拦截并改变 JS 引擎的底层操作,如数据读取.属性定义.函数构造等一系列操作.ES6 通过对这些底层内置对象的代理陷阱和反射函数,让开发者能进一步接近 JS 引擎的能力. 一.代 ...
- JavScript 日期格式化
JavScript 日期格式化 //日期格式化 function formatDate(date,fmt) { if(date == null || typeof (date) == undefine ...
- 手动加载B120i/B320i阵列卡驱动安装RHEL7.0
实验设备: Micro server Gen8(B120i) DL360e Gen8(B320i) 目录 一.前期准备... 1 二.加载阵列卡驱动... 11 三.手动分区... 21 四.安装设置 ...
- ELK之elasticsearch5.6的安装和head插件的安装
这里选择的elasticsearch为5.6的新版本,根据官方文档有几种暗装方式: https://www.elastic.co/guide/en/elasticsearch/reference/cu ...
- httpd结合php的fpm模式
httpd2.4版本的编译安装,不再赘述,查看上一篇:http://www.cnblogs.com/jsonhc/p/7134053.html 从官网下载php源码包:php-5.6.30.tar.b ...
- 《JAVA程序设计》第五次实验报告
20145333 实验五 Java网络编程及安全 北京电子科技学院(BESTI)实验报告 课程:Java程序设计 班级:1453 指导教师:娄嘉鹏 实验日期:2016.05.06 18:30-21:3 ...
- IT最新最火的网络词汇*2*(文章来源电商)
P2P.P2C .O2O .B2C.B2B.C2C等等最新最火的网络用词直接将我们都弄晕了,特此今天将这些划时代意义的词汇总结起来,若有什么不足之处,希望各位评论指正. 大致意思为: 1. ...