条件

  • 使用两个类设计,Message——表示电子邮件消息,Folder——表示消息目录。
  • 每个Message可以出现在多个Folder中。
  • 修改某一条Message,它在它所在的所有Folder中都会被修改。
  • Message使用一个set保存它所在的Folder的Folder指针。Folder也会用set保存它包含的Message的Message指针。
  • Message要有save和remove操作,向一个给定的Folder添加或删除一条Message。Folder也得有类似的操作。
  • 拷贝一个Message,将会拷贝其消息内容和保存Folder指针的set。同时每个包含此消息的Folder都添加一个指向新创建的Message的指针;销毁一个Message时,也要从包含此Message的所有Folder中删除指向此Message的指针。
  • 将一个Message赋予另一个Message时,左侧的Message会被右侧代替。同时更新Folder,将保存左侧Message的Folder中将它删除,然后添加右侧的Message

实现

框架

class Message
{friend class Folders;
public:explicit Message(const string &str = "") : contents(str) {}Message(const Message&);Message& operator=(const Message&);~Message();void save(Folder&);void remove(Folder&);
private:string contents;set<Folder*> folders;//将本Message添加到指向参数的Folder中void add_to_Folders(const Message&);//从folders中的每个Folder中删除本Messagevoid remove_from_Folders();
};

save和remove成员

void Message::save(Folder &f)
{//添加到folders,表示这个Folder保存了本信息folders.insert(&f);//将本信息添加到f的Message集合中f.addMsg(this);
}
void Message::remove(Folder &f)
{folders.erase(&f);f.remMsg(this);
}

拷贝控制成员

拷贝构造函数

拷贝一个Message,将会拷贝其消息内容和保存Folder指针的set。同时每个包含此消息的Folder都添加一个指向新创建的Message的指针

包含此消息的Folder们保存在folders中,所以如果拷贝一个Message,就要遍历该Message的folders,对其中每个Folder都要添加一个指向拷贝的新指针。拷贝构造函数和拷贝赋值运算符运算符都要完成这个工作,所以定一个一个函数完成这个公共工作(一般这种公共工作都是private的)

void add_to_Folders(const Message &m)
{for (auto f : m.folders)f->addMsg(this);
}

拷贝构造函数如下:

Message::Message(const Message &m) : contents(m.contents), folders(m.folders) { add_to_Folders(m); }

析构函数

而当一个Message被销毁时,必须从所有指向此Message的Folder中删除它。拷贝赋值运算符也要做这个工作,所以还是定义一个private的函数:

void Message::remove_from_Folders()
{for (auto f : folders)f->remMsg(this);
}

tips:拷贝赋值运算符通常执行拷贝构造函数和析构函数中也要做的工作。这种情况下,公共的工作应该作为函数放在private中

同时就能定义析构函数:

Message::~Message() { remove_from_Folders(); }

拷贝赋值运算符

左侧的Message被右侧替代,就相当于左侧的Message被销毁(遍历左侧的folders,删除指向自己的Folder),然后拷贝为右侧的Message(遍历右侧的folders,添加指向拷贝的新指针)

Message& Message::operator=(const Message &rhs)
{remove_from_Folders();contents = rhs.contents;folders = rhs.folders;add_to_Folders(rhs);return *this;
}

自己的Message和Folder类

  • 实现了对应的Folder类
  • 添加了addFldr()函数和rmvFldr()函数,分别实现向当前Message对象插入/删除一个Folder
class Folder
{friend class Message;
public:explicit Folder(const string &str = "") : title(str) {}Folder(const Folder&);Folder& operator=(const Folder&);~Folder() { remove_from_Message(); }
private:string title;set<Message*> msgs;void add_to_Message(const Folder &f){for (auto m : f.msgs)m->addFldr(this);}void remove_from_Message(){for (auto m : msgs)m->rmvFldr(this);}void remMsg(Message *m) { msgs.erase(m); }void addMsg(Message *m) { msgs.insert(m); }
};
Folder::Folder(const Folder &f) : title(f.title), msgs(f.msgs)
{//拷贝构造新的Folder//将老Folder消息集里的消息的set都添加上新Folder的指针add_to_Message(f);
}
Folder& Folder::operator=(const Folder &f)
{//拷贝赋值运算符函数,同时执行拷贝构造函数功能和析构函数功能remove_from_Message();title = f.title;msgs = f.msgs;add_to_Message(f);return *this;
}
class Message
{public:explicit Message(const string &str = "") : contents(str) {}Message(const Message &m) : contents(m.contents), folders(m.folders) { add_to_Folders(m); }Message& operator=(const Message&);~Message() { remove_from_Folders(); }void saveTo(Folder &f){folders.insert(&f);f.addMsg(this);}void addFldr(Folder *f) { folders.insert(f); }void removeFrom(Folder &f){folders.erase(&f);f.remMsg(this);}void rmvFldr(Folder *f) { folders.erase(f); }
private:string contents;set<Folder*> folders;void add_to_Folders(const Message &m){for (auto f : m.folders)f->addMsg(this);}void remove_from_Folders(){for (auto f : folders)f->remMsg(this);}};
Message& Message::operator=(const Message &rhs)
{remove_from_Folders();contents = rhs.contents;folders = rhs.folders;add_to_Folders(rhs);return *this;
}

给Message类加上移动构造函数和移动赋值运算符

Message有string和contents和set的folders,如果用拷贝会比较耗时耗力,利用移动控制能避免产生额外开销。接管了旧Message的资源后就要更新folders,将旧Message换成接管了旧Message的新Message。用一个函数来实现这个操作:

void move_Folders(Message *m)
{folders = std::move(m->folders); //调用set的移动赋值运算符for (auto f : folders){f->remMsg(m);f->addMsg(this);}m->folders.clear();//将老m置于可析构状态//确保销毁m没有别的影响
}
class Message
{public:explicit Message(const string &str = "") : contents(str) {}Message(const Message &m) : contents(m.contents), folders(m.folders) { add_to_Folders(m); }//移动构造函数,因为是接管m,所以要从Floder中删除老的m,添加成新的接管了m的左侧对象Message(Message &&m) : contens(std::move(m.contents)) { move_Folders(&m); }Message& operator=(const Message &rhs){remove_from_Folders();contents = rhs.contents;folders = rhs.folders;add_to_Folders(rhs);return *this;}//移动赋值运算符Message& operator=(Message &rhs){if (this != &rhs){remove_from_Folders();contents = std::move(rhs.contents);move_Folders(&rhs);}return *this;}~Message() { remove_from_Folders(); }void saveTo(Folder &f){folders.insert(&f);f.addMsg(this);}void addFldr(Folder *f) { folders.insert(f); }void removeFrom(Folder &f){folders.erase(&f);f.remMsg(this);}void rmvFldr(Folder *f) { folders.erase(f); }
private:string contents;set<Folder*> folders;void add_to_Folders(const Message &m){for (auto f : m.folders)f->addMsg(this);}void remove_from_Folders(){for (auto f : folders)f->remMsg(this);}void Message::move_Folders(Message *m){folders = std::move(m->folders); //调用set的移动赋值运算符for (auto f : folders){f->remMsg(m);f->addMsg(this);}m->folders.clear();//将老m置于可析构状态}
};
Message& Message::operator=(const Message &rhs)
{remove_from_Folders();contents = rhs.contents;folders = rhs.folders;add_to_Folders(rhs);return *this;
}

拷贝控制示例——Message和Folder相关推荐

  1. C++Primer笔记——拷贝控制

    CHAPTER13-拷贝控制(C++ Primer笔记) 13.1 拷贝.赋值与销毁 13.1.1 拷贝构造函数 13.1.2 拷贝赋值运算符 13.1.3 析构函数 13.1.4 三/五法则 13. ...

  2. C++ primer 第13章 拷贝控制

    文章目录 前言 拷贝.赋值与销毁 拷贝构造函数 合成拷贝构造函数 拷贝初始化和直接初始化 拷贝初始化的发生: 参数和返回值 拷贝初始化的限制 拷贝赋值运算符 重载赋值运算符 合成拷贝赋值运算符 析构函 ...

  3. C++ primer 第13章 拷贝控制

    文章目录 前言 拷贝.赋值与销毁 拷贝构造函数 合成拷贝构造函数 拷贝初始化和直接初始化 拷贝初始化的发生: 参数和返回值 拷贝初始化的限制 拷贝赋值运算符 重载赋值运算符 合成拷贝赋值运算符 析构函 ...

  4. 《C++ Primer》读书笔记——第十三章_拷贝控制

    一个类有5种特殊的成员函数:拷贝构造函数.拷贝赋值运算符.移动构造函数.移动赋值运算符.析构函数.如果没有定义这些拷贝控制成员,编译器会自动为它定义缺失的操作. A a; A b = a;//报错 1 ...

  5. C++ Primer 第十三章 拷贝控制

    当定义一个类时,我们显式或隐式指定在此类型的对象执行拷贝,移动,赋值,销毁时做什么,通过拷贝构造函数,拷贝赋值运算符,移动构造函数,移动赋值运算符和析构函数. 拷贝赋值与销毁 如果构造函数的第一个参数 ...

  6. 拷贝控制——拷贝控制和资源管理,交换操作,对象移动

    一.拷贝控制和资源管理 通常,管理类外资源的类必须定义拷贝控制成员,这种类需要通过析构函数来释放对象所分配的资源. 为了定义这些成员,我们首先必须确定此类型对象的拷贝语义.一般来说,有两种选择:可以定 ...

  7. C++ Primer 5th笔记(chap 13 拷贝控制)实例1

    1. Folder和Message的类设计 2. Messager.h class Message {friend void swap(Message&, Message&);frie ...

  8. c++ primer 5th第13章拷贝控制知识点和自编习题答案

    首先,先给大家提个醒.在网上的随书源代码里关于hasptr类的类指针版本编写的移动构造函数.移动赋值运算符.和析构函数部分是有错误的.大家可以把hasptr累指针版本(里面带移动构造函数和移动赋值运算 ...

  9. maven 构建 springmvc + spring security 权限控制示例

    2019独角兽企业重金招聘Python工程师标准>>> maven 构建 springmvc + spring security 权限控制示例. 介绍 :Spring Securit ...

  10. 【C++】拷贝控制与资源管理

    1. 拷贝控制与资源管理 管理类外资源的类必须定义拷贝控制成员.如P447中所见,这种类需要通过析构函数来释放对象所分配的资源.一旦一个类需要析构函数,那么几乎可确定它也需要一个拷贝构造函数和一个拷贝 ...

最新文章

  1. 转:【CSS/JS学习】如何实现单行/多行文本溢出的省略(...)--老司机绕过坑道的正确姿势...
  2. 腾讯开源基于 mmap 的高性能 key-value 组件 MMKV
  3. [跟我学UML] UML类图中的泛化
  4. 2010年8月blog汇总:敏捷个人和OpenExpressApp之建模支持
  5. 多图 | 搞懂volatile和synchronized的区别
  6. 光纤光缆市场需求高于预期 我国将迎来流量经济
  7. Python基础-XML模块
  8. Configured broker.id 2 doesn‘t match stored broker.id 3 in meta.properties
  9. Myesclipe+SSH+jsp+mysql+tomcate实现一个简单的CRM客户关系管理系统
  10. wkhtmltopdf 水印 背景_wkhtmltopdf + echarts 转 PDF
  11. 汽车系统实现--搜索功能
  12. vue —— 利用 viewport 进行适配
  13. Python txt转换为excel
  14. 怎么用计算机扫描照片,怎么扫描图片上的文字-无需扫描仪,教你三招轻松搞定文字识别!...
  15. [机器学习]给机器学习面试者的十项建议
  16. 日有所思(6)——直流电机注意点
  17. 小程序-视图与逻辑-页面导航
  18. 微信小程序 之radio应用实例(选择收货地址)
  19. 电商项目中的经典问题
  20. Android SDK开发包国内下载地址

热门文章

  1. 外贸常用术语_外贸常用句子
  2. 2.5万字讲解DDD领域驱动设计,从理论到实践掌握DDD分层架构设计,赶紧收藏起来吧
  3. 2019春运抢票攻略:凭借单身三十年的手速干死一批黄牛党
  4. 趣学Spring:一文搞懂Aware、异步编程、计划任务
  5. ng4 html路由跳转,Angular4.x通过路由守卫实现动态跳转界面步骤详解
  6. 不是因为寂寞才想你计算机谱子,不是因为寂寞才想你曲谱
  7. 日更第1天:Linux常用命令之dnf用法
  8. 数据结构学习笔记(考研 笔记 完结 西电)
  9. Java面试知识点(六十三)Java反射
  10. 记录自已学习之ARM汇编语言之bic和orr