#pragma once
#include<string>
#include<set>
using namespace std; class Message
{
friend class Folder;
friend void swap(Message &lhs, Message &rhs);
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;
void add_to_Folders(const Message&);
void remove_from_Folders();
}; class Folder
{
public:
Folder(const Folder&);//拷贝构造函数
Folder& operator=(const Folder);//拷贝赋值运算符,采用非引用类型,实现出现自赋值情况时,也能成功,但多了一次拷贝构造
~Folder(); //析构函数
void addMsg(Message *); //添加message
void remMsg(Message *); //去除message
private:
set<Message*> Mes;
void addAllMsg(); //拷贝构造函数和拷贝赋值预算符的辅助函数
void removeAllMsg(); //拷贝赋值运算符和析构函数的辅助函数
}; void Folder::addMsg(Message *m)
{
if(Mes.find(m)==Mes.end())//防止在调用m->save(*this)时的从复插入(虽然重复插入对于set来说没什么关系)
Mes.insert(m);
if (m->folders.find(this) == m->folders.end())//给递归调用一个结束条件,防止无限调用
m->save(*this);
} void Folder::remMsg(Message *m)
{
if (Mes.find(m) != Mes.end())//防止在调用m->remove(*this)时的从复删除(虽然重复删除对于set来说没什么关系)
Mes.erase(m);
if (m->folders.find(this) != m->folders.end())//给递归调用一个结束条件,防止无限调用
m->remove(*this);
} void Folder::addAllMsg() //拷贝构造函数和拷贝赋值预算符的辅助函数
{
for (auto &m : Mes) //对Mes集合中的每一个指针对象都调用save()函数
m->save(*this);
} Folder::Folder(const Folder &f)
{
Mes = f.Mes; //将f中数据成员拷贝过来
addAllMsg(); //调用addALLMsg将这个Folder添加到所有对应的message中去
} void Folder::removeAllMsg() //拷贝赋值运算符和析构函数的辅助函数
{
for (auto &m : Mes) //对Mes集合中的每一个指针对象都调用remover()函数
m->remove(*this);
} Folder& Folder::operator=(const Folder f)//采用非引用类型是为了保护出现自赋值的情况时,也能正常运行
{
removeAllMsg(); //将数据成员中所包含的所有message都调用remove()函数,实现删除这个文件夹的作用
Mes = f.Mes; //将新的数据成员拷贝过来
addAllMsg(); //将数据成员中所包含的所有message都调用remover()函数,完成为这个文件夹赋值右侧文件夹的步骤
return *this;
} Folder::~Folder()
{
removeAllMsg(); //将数据成员中所包含的所有message都调用remove()函数,实现删除这个文件夹的作用
} void Message::save(Folder &f)
{
folders.insert(&f);
f.addMsg(this);
} void Message::remove(Folder &f)
{
folders.erase(&f);
f.remMsg(this);
} void Message::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);
} void Message::remove_from_Folders()
{
for (auto f : folders)
f->remMsg(this);
} Message::~Message()
{
remove_from_Folders();
} Message& Message::operator=(const Message rhs)
{
remove_from_Folders();
contents = rhs.contents;
folders = rhs.folders;
add_to_Folders(rhs);
return *this;
} void swap(Message &lhs, Message &rhs)
{
set<Folder*> lfolders = lhs.folders;
set<Folder*> rfolders = rhs.folders;
for (auto f : rhs.folders)
f->remMsg(&rhs);
for (auto f : lhs.folders)
f->remMsg(&rhs);
lhs.folders = rhs.folders;
rhs.folders = lhs.folders;
swap(lhs.contents, rhs.contents);
for (auto f : lhs.folders)
f->addMsg(&lhs);
for (auto f : rhs.folders)
f->addMsg(&rhs);
}

C++primer 练习13.36的更多相关文章

  1. C++primer 练习13.44

    13.44:编写标准库string类的简化版本,命名为String.你的类应该至少有一个默认构造函数和一个接受C 风格字符串指针参数的构造函数.使用allocator为你的String类分配所需内存 ...

  2. C++primer 练习13.39

    13.39 编写你自己版本的StrVec,包括自己版本的reserve,capacity(参见9.4节,第318页)和resize(参见9.3.5节,第314页) 13.40 为你的StrVec类添加 ...

  3. 【C++ Primer 第13章】2. 拷贝控制和资源管理

    拷贝控制和资源管理 • 类的行为像一个值.意味着它应该有自己的状态,当我们拷贝一个像值得对象时,副本和原对象是完全独立的,改变副本不会对原对象有任何影响. • 行为像指针的类则共享状态.当我们拷贝一个 ...

  4. 【C++ Primer 第13章】1. 拷贝控制、赋值和销毁

    拷贝控制.赋值和销毁 如果一个构造函数的第一个参数是自身类的引用,且额外的参数都有默认值,则此构造函数是拷贝控制函数(拷贝构造函数不应该是explicit的). 如果我们没有为一个类定义拷贝构造函数, ...

  5. 【C++ Primer 第13章】3. 交换操作

    交换操作 class HasPtr { friend void swap(HasPtr &rhs, HasPtr &yhs); //其他成员定义 }; void swap(HasPtr ...

  6. [C++ Primer] : 第13章: 拷贝控制

    拷贝, 赋值与销毁 当定义一个类时, 我们显示地或隐式地指定在此类型的对象拷贝, 移动, 赋值和销毁时做什么. 一个类通过定义5种特殊的成员函数来控制这些操作, 包括: 拷贝构造函数, 拷贝赋值运算符 ...

  7. C++ primer chapter 13

    拷贝 赋值 销毁 拷贝构造函数 如果一个构造函数第一个参数是自身的引用,而且任何额外参数都有默认值,则此构造函数是拷贝构造函数拷贝构造函数的第一个类型必须是引用:如果参数不是引用类型,那么调用不会成功 ...

  8. 【C++ Primer 第13章】6.对象移动

    右值引用 左值和右值 (1)两者区别: ①左值:能对表达式取地址.或具名对象/变量.一般指表达式结束后依然存在的持久对象. ②右值:不能对表达式取地址,或匿名对象.一般指表达式结束就不再存在的临时对象 ...

  9. 【C++ Primer 第13章】5. 动态内存管理类

    StrVec类的设计 [题目描述]:我们将实现标准库vector类的一个简化版本,我们所做的一个简化是不使用模板,我们类只用于string,因此,它被命名为StrVec. #include<io ...

随机推荐

  1. 【转】Android Drawable Resource学习(十一)、RotateDrawable

    对另一个drawable资源,基于当前的level,进行旋转的drawable. 文件位置: res/drawable/filename.xml文件名即资源名 编译数据类型: 指向 RotateDra ...

  2. Java连接Oracle

    Process myProcess = Runtime.getRuntime().exec("ipconfig"); InputStreamReader ir = new Inpu ...

  3. [转]LOG4J汇编教程edit Z10

    摘自:http://wucuixia.blog.sohu.com/12057602.html LOG背景 我们在编程时经常不可避免地要使用到一些日志操作,比如开发阶段的调试信息.运行时的日志记录及审计 ...

  4. form表单reset重置按钮

    如果ajax提交完数据,后想清空表单内容 ,以前都是用这个方法$("#id").val(""); 一个一个清空的,其实可以在form表单中加个隐藏的<in ...

  5. MIT牛人解说数学体系(转载)

    原文网址:http://www.guokr.com/post/442622/ 在过去的一年中,我一直在数学的海洋中游荡,research进展不多,对于数学世界的阅历算是有了一些长进. 为什么要深入数学 ...

  6. VB TreeView控件使用详解

    来源:http://www.newxing.com/Tech/Program/VisualBasic/TreeView_587.html 三小时快速掌握TreeView树状控件的使用.能不能掌握控件的 ...

  7. Linux后台开发常用工具

    内存分析工具valgrind valgrind辅助工具qcachegrind 可视化查看valgrind结果 淘宝DBA团队发布的监控脚本,使用perl开发,可以完成对linux系统和MySql相关指 ...

  8. 常​用​的​邮​箱​服​务​器​(​S​M​T​P​、​P​O​P​3​)​地​址​、​端​口

    常用的邮箱服务器(SMTP.POP3)地址.端口 gmail(google.com)  POP3服务器地址:pop.gmail.com(SSL启用 端口:995)  SMTP服务器地址:smtp.gm ...

  9. TMS320C54x系列DSP的CPU与外设——第8章 流水线

    第8章 流水线 本章描述了TMS320C54x DSP流水线的操作,列出了对不同寄存器操作时的流水线延迟周期.(对应英语原文第7章) 8.1 流水线操作 TMS320C54x DSP有一个6段的指令流 ...

  10. MongoDB 3.0.6的主,从,仲裁节点搭建

    在MongoDB所在路径创建log和data目录mkdir logmkdir data 在data目录下 创建master.slaver.arbiter路径 mkdir master mkdir sl ...