前言

标题一看似乎是非常直观简单,没必要特别写下一篇随便记录。

然而,在实际开发中,你会发现做到这一点对于经验不足的 C++ 程序员来说绝对是一个挑战。

要做到复制每一个成分,就一定小心下面说到的两点。

第一点

类中新增了成员变量之后,需要在自定义的构造函数,析构函数,赋值运算符重载函数,拷贝构造函数中做出相应调整。

请看下面一个例子:

 1 // 记录调用信息
 2 void logCall(const std::string & funcName);
 3
 4 // 顾客类
 5 class Customer {
 6 public:
 7     //......
 8     Customer(const Customer & rhs);    // 自定义拷贝构造函数
 9     Customer & operator=(const Customer & rhs);    // 自定义赋值运算符
10     //......
11 private:
12     std::string name;
13 };
14
15 Customer::Customer(const Customer & rhs)
16     : name(rhs.name)
17 {
18     logCall("Customer copy constructor");
19 }
20
21 Customer & Customer::operator=(const Customer &rhs) {
22     logCall("Customer copy assignment operator");
23     name = rhs.name;
24     return *this;
25 }

这段代码定义了一个顾客类,每次调用它的拷贝构造函数以及赋值运算符重载函数就会记录下这次操作。

这里看起来一切都很美好,也确实是这样的。

但当你往这个类中添加了一个成员变量,不小心的话就会出问题了:

 1 class Data { /*......*/ };
 2 // 顾客类
 3 class Customer {
 4 public:
 5     //......
 6     Customer(const Customer & rhs);    // 自定义拷贝构造函数
 7     Customer & operator=(const Customer & rhs);    // 自定义赋值运算符
 8     //......
 9 private:
10     std::string name;
11     Data lastTransaction;        // 看这里! 定义了一个新的变量
12
13 };
14
15 Customer::Customer(const Customer & rhs)
16     : name(rhs.name)
17 {
18     logCall("Customer copy constructor");
19 }
20
21 Customer & Customer::operator=(const Customer &rhs) {
22     logCall("Customer copy assignment operator");
23     name = rhs.name;
24     return *this;
25 }

这里,你必须要对自定义的构造函数,拷贝构造函数,赋值运算符重载函数都做出相应的修改才行。

第二点

子类对象的自定义赋值运算符重载函数,拷贝构造函数要写入父类成员拷贝的相关语句。

还是以上面的实例来进行分析,这里我设计了一个 PriorityCustomer 类继承 Customer 类,如果要自定义它的拷贝构造函数和赋值运算符,请问这样做对吗?

 1 class PriorityCustomer : public Customer {
 2 public:
 3     //......
 4     PriorityCustomer(const PriorityCustomer & rhs);    // 自定义拷贝构造函数
 5     PriorityCustomer & operator=(const PriorityCustomer & rhs);    // 自定义赋值运算符
 6     //......
 7 private:
 8     int priority;
 9 };
10
11 PriorityCustomer::PriorityCustomer(const PriorityCustomer & rhs)
12     : priority(rhs.priority)
13 {
14     logCall("PriorityCustomer copy constructor");
15 }
16
17 PriorityCustomer & PriorityCustomer::operator=(const PriorityCustomer &rhs) {
18     logCall("PriorityCustomer copy assignment operator");
19     priority = rhs.priority;
20     return *this;
21 }

答案是否定的。因为这两个函数中,只拷贝了子类对象新定义成员,它们继承自父类部分却没有拷贝。

小结

再说一点就是,如果你发现自定义的拷贝构造函数和赋值运算符重载函数有代码重复,那么最好的做法是建立一个新的函数让它们来调用;不要让拷贝构造函数和赋值运算符重载函数相互调用,这是行不通的。

第十篇:复制对象时切记复制每一个成分相关推荐

  1. 你会copying了吗?(Effective C++ 12 复制对象时勿忘其每一个成分)

    12. 复制对象时勿忘其每一个成分 为derived class写copying函数时,必须很小心地复制其base class成分.那些成分往往是private,故无法直接访问它们,应该让derive ...

  2. Java提升篇:对象克隆(复制)

    引论 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,sho ...

  3. 条款12:复制对象时勿忘其每一个部分

    设计良好的面向对象系统会将对象的内部封装起来,只留两个函数负责对象拷贝,即copy构造函数与copy assignment操作符.编译器会在必要的时候为类创建coping函数,并说明这些"编 ...

  4. 数据库备份 Mysql table '' doesn`t exist .(mysql数据库复制迁移时除了复制文件夹外还要复制data目录下的ibdata1文件)

    今天在整理一个网站的时候,操作系统由于系统自动更新导致一直出现系统蓝屏死机,唉,悲剧了,于是重新安装了系统 windows server 2008 enterprise 32bit. 详情: 系统安装 ...

  5. JavaScript 复制对象与Object.assign方法无法实现深复制

    在JavaScript这门语言中,数据类型分为两大类:基本数据类型和复杂数据类型.基本数据类型包括Number.Boolean.String.Null.String.Symbol(ES6 新增),而复 ...

  6. 复制对象clone(深复制和浅复制)

    Java中对象的创建 clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以会复制对象.所谓的复制对象,首先要分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象.那 ...

  7. Pycharm复制代码时括弧前出现空格

    今天在pycharm里面复制代码时,出现了一个问题,复制完一段代码后,括弧前都自动添加了一个空格,如下图: 这是源代码: files = os.listdir(data_path) count_of_ ...

  8. python复制字典_python字典复制

    python学习系列--深拷贝和浅拷贝 概念 普通情况下,复制一个对象是不会新开辟内存空间的,只是把新的对象名称指向原有的内存地址,这种操作其实不是算是拷贝,只是新的引用.把新的对象置于新的内存空间中 ...

  9. HashMap get不出对象时出错 解决

    为什么80%的码农都做不了架构师?>>>    如题: Map map = new HashMap();   map.put("1", "A" ...

  10. ADO.NET 2.0 - 读者询问能否使用 SqlBulkCopy 对象来大量复制文字文件

    我们曾经在「Visual Basic 2005 档案 IO 与数据存取秘诀」一书的第 10 章说明如何使用 SqlBulkCopy 对象来执行大量复制作业.有读者询问,是否可以使用 SqlBulkCo ...

最新文章

  1. MongoDB —— 概念简述
  2. python linux编程与window编程_Python3如何在Windows和Linux上打包
  3. rabbitmq如何保证消息不被重复消费_RabbitMQ保证消息可靠投递与消费的正确使用姿势...
  4. java索引序列_视图、序列、索引
  5. 爱计算机辅助筛查肺结节,计算机辅助检测系统提高CT肺结节检出方式的研究
  6. python 存redis失败无提示_python如何关闭redis
  7. 拼装sql_2020最新最全面的SQL优化干货总结
  8. win98 老电脑 文件导出_UGNX利器:轻量化建模,很多人还傻傻的关注电脑配置
  9. 点击触发ajax重复提交表单,屡次连续点击致使Ajax重复提交
  10. python 微信步数修改
  11. flex布局及flex实现常见的前端布局
  12. 西数完善黑盘系列 3TB黑盘终面市
  13. 详解会议中控系统及其优点特点有哪些?
  14. 智慧工地具有哪些社会意义?
  15. CornerNet,CenterNet关键代码解读: kp,_decode,left pooling
  16. 零基础如何学素描——什么是结构素描…
  17. 进化算法可以不再需要计算集群,开普敦大学的新方法用一块GPU也能刷新MNIST记录...
  18. ソ前奏诗存档_如何评价日本摇滚乐团 和楽器バンド(和乐器乐团)?
  19. 适用OpenCV读取网络摄像头(海康萤石 CS-C3S-52WEFR 1080P)的视频流
  20. 三步 让你的 vscode 自动编译ts文件

热门文章

  1. git stash (保存当前的工作现场)
  2. CodeBlocks常用操作快捷键
  3. python读取dat文件并保存为Excel格式
  4. PHP使用redis防止大并发下二次写入
  5. mysql多个left join
  6. python 加减法 负数_python解决两位数加减法快速出题问题
  7. hadoop介绍及伪分布式搭建
  8. go语言学习之切片、字典、defer语句
  9. 数据库与java操作小有体会
  10. java麻麻_知了堂教你不怂密密麻麻的Java代码