稍微深入点理解C++复制控制【转】
通过一个实例稍微深入理解C++复制控制过程,参考资料《C++ primer》,介绍点基本知识:
1、在C++中类通过特殊的成员函数:复制构造函数、赋值操作符和析构函数来控制复制、赋值和撤销该类的对象时会发生什么。
2、复制构造函数(copy constructor)是一种特殊的构造函数,具有单个形参,该形参(常用const)是对该类类型的引用;
- 当定义一个新对象并用一个同类型的对象对它进行初始化时,将显示使用复制构造函数;
- 当将该类的对象传递给函数或从函数返回该类型的对象时,将隐式使用复制构造函数。
3、复制构造函数可用于:
- 根据另一个同类型的对象显示或隐式初始化一个对象;
- 复制一个对象,将它作为实参传给一个函数;
- 从函数返回时复制一个对象;
- 初始化顺序容器中的元素;
- 根据元素初始化式列表初始化数组元素。
4、如果我们在类体中没有定义复制构造函数,编译器就会为我们合成一个复制构造函数。与合成的默认构造函数不同,即使我们定义了其他构造函数,也会合成复制构造函数。
合成复制构造函数的行为:执行逐个成员初始化,将新对象初始化为原对象的副本。
有些类经常有的数据成员是指针,这时我们必须对复制对象时发生的事情加以控制,否则当复制的对象析构或者删除时,对象中的指针不再指向有效对象,则会出现悬垂指针情况,这时我们必须要定义自己的复制构造函数。
5、有些类需要完全禁止复制,例如,iostream类就不允许复制,如果不想复制,则应明确禁止,可以将复制构造函数声明为private,并且不定义。
6、赋值操作符(assignment operator):同复制构造函数一样,如果在类体中没有定义赋值操作符,编译器也会为我们合成一个赋值操作符。它会执行逐个成员复制:右操作数对象的每个成员赋值给左操作数对象的对应成员。
如:

Sales_item& Sales_item::operator=(const Sales_item &rhs)
{
isbn = rhs.isbn;
units_sold = rhs.units_sold;
revenue = rhs.revenue;
return *this;
}

7、析构函数(destructor):是构造函数的互补,当对象超出作用域或动态分配的对象(new、malloc)被删除时,将自动应用析构函数。
下面通过一个实例详细说明复制构造函数、赋值操作符、析构函数的调用机制,代码中已有详细解释,故在此不再赘述~

1 /************************************************
2 *
3 * 内容摘要:定义Expm1类,该类给出复制控制成员和其他构造函数
4 * 用不同方式使用Expm1类型的对象:
5 * 作为非引用形参和引用形参传递,动态分配
6 * 作为函数返回值,进行赋值操作,作为元素放在vector容器中。
7 * 研究何时执行哪个构造函数和复制控制成员
8 *
9 * 日 期:2012.8.27 by Jacky Liu
10 *
11 ************************************************/
12
13 #include <vector>
14 #include <iostream>
15
16 struct Expm1
17 {
18 //默认构造函数
19 Expm1()
20 {
21 std::cout<<"Expm1()"<<std::endl;
22 }
23
24 //复制构造函数
25 Expm1(const Expm1 &)
26 {
27 std::cout<<"Expm1 (const Expm1&)"<<std::endl;
28 }
29
30 //复制操作符
31 Expm1 & operator = (const Expm1 &)
32 {
33 std::cout<<"operator = (const Expm1&)"<<std::endl;
34 return *this;
35 }
36
37 //析构函数
38 ~Expm1()
39 {
40 std::cout<<"~Expm1()"<<std::endl;
41 }
42 };
43
44 void func1(Expm1 obj) //形参为Expm1对象
45 {}
46
47 void func2(Expm1 & obj) //形参为Expm1对象的引用
48 {}
49
50 Expm1 func3()
51 {
52 Expm1 obj;
53 return obj; //返回Expm1对象
54 }
55
56 int main()
57 {
58 std::cout<<"1-------------------------------------"<<std::endl<<std::endl;
59
60 Expm1 eobj; //调用默认构造函数创建Expm1对象eobj
61
62 std::cout<<"2-------------------------------------"<<std::endl<<std::endl;
63
64 func1(eobj); //调用复制构造函数
65 //将形参Expm1对象创建为实参Expm1对象的副本
66 //函数执行完毕后调用析构函数撤销形参Expm1对象
67
68 std::cout<<"3-------------------------------------"<<std::endl<<std::endl;
69
70 func2(eobj); //形参为Expm1对象的引用,无需调用复制构造函数传递实参
71
72 std::cout<<"4-------------------------------------"<<std::endl<<std::endl;
73
74 eobj = func3(); //调用默认构造函数创建局部Expm1对象
75 //函数返回时调用复制构造函数创建作为返回值副本的Expm1对象
76 //然后调用析构函数撤销局部Expm1对象
77 //然后调用赋值操作符
78 //执行完赋值操作后
79 //调用析构函数撤销作为返回值副本的Expm1对象
80
81 std::cout<<"5-------------------------------------"<<std::endl<<std::endl;
82
83 Expm1 *p = new Expm1; //调用默认构造函数动态创建Expm1对象
84
85 std::vector<Expm1> evec(3); //调用默认构造函数创建一个临时值Expm1对象
86 //调用复制构造函数,将临时值Expm1对象复制到vector容器evec的每个元素
87 //调用析构函数撤销临时值Expm1对象
88 //按以上重复三次
89
90 std::cout<<"6-------------------------------------"<<std::endl<<std::endl;
91 delete p; //调用析构函数撤销动态创建的Expm1对象
92
93 system("pause");
94 return 0; //eobj及evec生命期结束,自动调用析构函数撤销
95
96 }

运行结果:仔细观察运行结果的执行情况,可以深入理解C++中的复制控制机制~

稍微深入点理解C++复制控制【转】的更多相关文章
- 深入理解redis复制原理
原文:深入理解redis复制原理 1.复制过程 2.数据间的同步 3.全量复制 4.部分复制 5.心跳 6.异步复制 1.复制过程 从节点执行 slaveof 命令. 从节点只是保存了 slaveof ...
- C++继承与构造函数、复制控制
每个派生类对象由派生类中定义的(非static)成员加上一个或多个基类子对象构成,因此,当构造.复制.赋值和撤销派生类型对象时,也会构造.复制.赋值和撤销这些基类子对象. 构造函数和复制控制成员不能继 ...
- C++ 复制控制之复制构造函数
7月26日更新: 过了这么长的时间回过头来看,发现文章中有几个点说错(用红字标出): 构造函数不是只有唯一一个参数,它也可以是多参数形式,其第二参数及后继以一个默认值供应. 不是没有声明复制控制函数时 ...
- C++ Primer 学习笔记_67_面向对象编程 --转换与继承、复制控制与继承
面向对象编程 --转换与继承.复制控制与继承 I.转换与继承 引言: 由于每一个派生类对象都包括一个基类部分,因此能够像使用基类对象一样在派生类对象上执行操作. 对于指针/引用,能够将派生类对象的指针 ...
- C++ Primer 随笔 Chapter 13 复制控制
1.复制控制包含的内容:复制构造函数.赋值操作符.析构函数 2.复制构造函数: a. 定义:只有单个形参,而且该形参是对本类类型的引用,这样的构造函数被成为复制构造函数 b. 适用情况: (1)根据一 ...
- C++Primer笔记之复制控制
复制控制这一节需要注意的地方不多,主要有以下几点: 1.定义自己的复制构造函数 什么时候需要定义自己的复制构造函数,而不用系统提供的,主要遵循以下的经验说明: 某些类必须对复制对象时发生的事情加以控制 ...
- C++拾遗(六)——复制控制
年前忙了几天,到现在才算是有空休息下来.先祝大家新年快乐,心想事成:)我也会发笑脸o.o 这篇博文主要介绍定义一个类型的对象时的复制控制方式,这部分内容之前有一定的了解但又浅尝辄止,始终感觉没能找到要 ...
- 嗯 第二道线段树题目 对左右节点和下标有了更深的理解 hdu1556
Color the ball Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)To ...
- 通过laravel理解IoC(控制反转)容器和DI(依赖注入)
原文地址: http://www.insp.top/learn-laravel-container ,转载务必保留来源,谢谢了! 容器,字面上理解就是装东西的东西.常见的变量.对象属性等都可以算是容器 ...
随机推荐
- BZOJ 4892 [Tjoi2017]dna 哈希+二分
自己简直是傻死了...对于位置想错了... 二分出来的是LCP长度$+1$,即每一次二分出来的最后一个点都是失配的,而就算失配也会跳过这个点:所以当$k<=3$且模式串$s2$的指针$>l ...
- 练习十六:Python日期格式应用(datetime)
练习:关于python日期格式应用练习.用python方法如何输出指定格式形式的日期 这里用到datetime模块,datetime模块重新封装了time模块,提供了更多接口,提供的类包括:date, ...
- sleuth使用说明(入门)
出发点: 微服务架构上通过业务来划分服务的,通过REST调用,对外暴露的一个接口,可能需要很多个服务协同才能完成这个接口功能,如果链路上任何一个服务出现问题或者网络超时,都会形成导致接口调用失败.随着 ...
- poj3254(状压dp入门第一道题,很详细)
题目链接:http://poj.org/problem?id=3254 学习博客:https://blog.csdn.net/harrypoirot/article/details/23163485 ...
- Unity [RequireComponent(typeof(组件名))]
- 了解【Docker】从这里开始
一.环境配置的难题 软件开发最大的难题之一就是环境配置的问题.现在用户环境纷乱复杂,并且由于开源社区的进一步推广和许多开源项目不停地迭代更新,项目可能会有越来越多的依赖以及越来越难管理的依赖版本,如何 ...
- <rhel6 mysql replication>
MySQL 支持单向.异步复制,复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器.主服务器将更新写入二进制日志文件,并维护文件的一个索引以跟踪日志循环.这些日志可以记录发送到从服务 ...
- 【翻译转载】【官方教程】Asp.Net MVC4入门指南(2):添加一个控制器
2. 添加一个控制器 · 原文地址:http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/adding-a-c ...
- [LeetCode]10. Regular Expression Matching正则表达式匹配
Given an input string (s) and a pattern (p), implement regular expression matching with support for ...
- Centos7.5搭建ELK-6.5.0日志分析平台
Centos7.5搭建ELK-6.5.0日志分析平台 1. 简介 工作工程中,不论是开发还是运维,都会遇到各种各样的日志,主要包括系统日志.应用程序日志和安全日志,对于开发人员来说,查看日志,可以实时 ...