c++ Message与Folder 拷贝 析构(没有动态空间的类)

1、两个类里边分别保存一个对方的set表,当前类有拷贝或者销毁时需要更新另一个类的set表。

2、两个类都需要访问对方的private成员,所以两互相为友元,这样的两个类必须声明在同一个".h"文件中否则会导致先编译的类使用了使用的另一类是不完全的。

分开在两个".h"文件中定义为出现如下结果:

A.h

class B;
class A{
friend class B;
...
}

A.cpp

void A::func_access_B{
访问B中的private成员 // 这个时候B还是不完全类,访问B的成员是错误的
}

B.h

void A::func_access_B{
class B {
friend class A;
...
}

B.cpp

void A::func_access_B{
void B::func_access_A {
访问A中的private成员 // 这个时候A已经完全声明过,访问A的成员是正确的。
}

两个在一个头文件中声明,一个文件中定义

A_B.h

class B;
class A {
friend class B;
...
}
class B {
friend class A;
...
}

A_B.cpp

void A::func_access_B {
访问B中的private成员 // 这个时候B已经完全声明过,访问B的成员是正确的。
}
void B::func_access_A {
访问A中的private成员 // 这个时候A已经完全声明过,访问A的成员是正确的。
}

Message_Folder.h

#include <set>
#include <string>
#include <iostream> using namespace std; #ifndef MESSAGE_FOLDER__H
#define MESSAGE_FOLDER__H class Folder;
class Message {
friend class Folder;
friend void swap(Message &, Message &);
friend void swap(Folder &, Folder &); public:
typedef enum {ADD = 0, REMOVE} update_mode;
Message(const string &msg = ""):contents(msg) {}
Message(const Message &msg);
Message &operator=(const Message &);
~Message(); void save(Folder &);
void remove(Folder &); string getContents() {return contents;}
void setContents(const string &c) {contents = c;}  
void display();
private:
string contents;
set<Folder*> folders;
void update_folder_set(const update_mode &);
};
void swap(Message &, Message &); class Folder {
friend class Message;
friend void swap(Message &, Message &);
friend void swap(Folder &, Folder &); public:
typedef enum {ADD = 0, REMOVE} update_mode; // 这个与Message中定义的enum不冲突,因为两个的作用域都只在类中。
Folder(const string &n = ""):name(n) {}
Folder(const Folder &);
Folder &operator=(const Folder &);
~Folder(); void save(Message &);
void remove(Message &); string getName() {return name;}
void setName(const string &n) {name = n;}
void display(); private:
string name;
set<Message*> messages;
void update_folder_set(const update_mode &);
};
void swap(Folder &, Folder &); #endif

Message_Folder.cpp

#include "Message_Folder.h"

//--------------- Message Part --------------//
// 将message(this)加入到某个Folder中去
// 这里要更新message(this)的set<Folder*>表和Folder中的set<Message*>表
void Message::save(Folder &f) {
folders.insert(&f); // 更新set<Folder*>表,指示这条message存在某个Folder中。
f.messages.insert(this); // 更新set<Message*>表,指示folder中有这条消息。
} // 将message(this)从某个Folder中去除
// 这里要更新message(this)的set<Folder*>表和Folder中的set<Message*>表
void Message::remove(Folder &f) {
folders.erase(&f);
f.messages.erase(this);
} // Message在拷贝和析构操作的时候,会复制一条message,或者销毁一条message
// message复制和销毁要同步更新这条message存在的folder的set<Message*>表
// 复制消息的时候,Folder中新增message,析构消息的时候Folder中删除消息。
void Message::update_folder_set(const update_mode &mode) {
if(mode == ADD) {
for(const auto &v : folders) {
v->insert(this);
}
} else {
for(const auto &v : folders) {
v->erase(this);
}
}
} // Message的拷贝构造函数
// Message拷贝后,拷贝的消息要出现在对应的Folder中
// 就需要更新原消息所在Folder,将新消息(this)加入到对应的Folder中
Message::Message(const Message &msg) : contents(msg.contents), folders(msg.folders) {
update_folder_set(ADD);
} // Message的拷贝赋值运算符
// Message在拷贝赋值的时候,左侧对象被覆盖(对应contents来说就是不存在了),要更新左侧对象对象所在Folder的set<Message*>表
// 左侧对象被右侧对象覆盖,左侧对象的set<Folder*>也被覆盖,这样要根据拷贝的set<Folder*>更新Folder中的set<Message*>表
Message &Message::operator=(const Message &msg) {
update_folder_set(REMOVE);
folders = msg.folders;
contents = msg.contents;
update_folder_set(ADD); return *this;
} // Message的析构函数
// Message析构后,消息不存在,所以要更新消息所在Folder的set<Message*>
Message::~Message() {
update_folder_set(REMOVE);
} // Message的交换函数
// 理论上是在vector<Message>调用sort的时候会调用这个函数,但是测试没有调用
// message交换了,也就是原对象对的message变了,这个时候先要销毁原来message对应的folder联系
// message交互后再重新建立message与folder的联系。
void swap(Message &lhs, Message &rhs) {
for(const auto &v : lhs.folders)
v->messages.erase(&lhs);
for(const auto &v : rhs.folders)
v->messages.erase(&rhs);
swap(lhs.contents, rhs.contents);
swap(lhs.folders, rhs.folders);
for(const auto &v : lhs.folders)
v->messages.insert(&lhs);
for(const auto &v : rhs.folders)
v->messages.insert(&rhs);
} void Message::display() {
for(const auto &v : folders)
cout<<v->getName()<<endl;
} //--------------- Folder Part --------------//
void Folder::save(Message &msg) {
folders.insert(&msg);
msg.folders.insert(this);
} void Folder::remove(Message &f) {
messages.erase(&msg);
msg.folders.erase(this);
} void Folder::update_message_set(const update_mode &mode) {
if(mode == ADD) {
for(const auto &v : messages) {
v->insert(this);
}
} else {
for(const auto &v : messages) {
v->erase(this);
}
}
} Folder::Folder(const Folder &f) : name(f.name), messages(f.messages) {
update_message_set(ADD);
}

测试程序

Message msg1("msg1");
Message msg2("msg2"); Folder fld1("folder1");
Folder fld2("folder2"); // 测试message类的操作更新folder类的联系(更新folder中的set表)
msg1.save(fld1); // 将msg1保存到folder1中。
cout<<"folder messages ..1"<<endl;
fld1.display(); // 输出msg1,folder1中有一条消息 Message msg3(msg1); // 用msg1拷贝构造msg3,msg1在Folder1中,msg3也会在folder1中
msg3.setContents("msg3"); // 将拷贝的contents="msg1",修改为"msg3"方便区分
cout<<"folder messages ..2"<<endl;
fld1.display(); // 输出msg1,msg3 Message msg4;
msg4 = msg1; // msg4为msg1的拷贝,msg4也会在Folder1中
msg4.setContents("msg4");
cout<<"folder messages ..3"<<endl;
fld1.display(); // 输出msg1,msg3,msg4 Message *msg5 = new Message(msg1); // 用msg1拷贝构造msg3,msg1在Folder1中,msg3也会在folder1中
msg5->setContents("msg5");
cout<<"folder messages ..4"<<endl;
fld1.display(); // 输出msg1,msg3,msg4,msg5 delete msg5; // 销毁msg5,msg5与folder1自动断开联系,即msg5从fld1中去除。
cout<<"folder messages ..5"<<endl;
fld1.display(); // 输出msg1,msg3,msg4 msg1.remove(fld1); // msg1从fld1中去除,手动断开联系
cout<<"folder messages ..6"<<endl;
fld1.display(); // 输出msg3,msg4 // 测试folder类的操作更新message类的联系(更新message中的set表)
fld2.save(msg1); // 将msg1保存到folder2中,现在msg1只出现在folder2中
cout<<"message1 folder ..1"<<endl;
msg1.display(); // 输出fld2 Folder fld3(fld2); // 用fld2拷贝构造fld3,fld2包含了msg1,那么fld3也要包含msg1,即msg1会被包含在fld3中。
fld3.setName("fld3"); // 修改fld3的名字,便于区分
cout<<"message1 folder ..1"<<endl;
msg1.display(); // 输出fld2,fld3 Folder fld4;
fld4 = fld2; // fld4为fld2的拷贝,fld4也要包含msg1
fld4.setName("fld4");
cout<<"message1 folder ..1"<<endl;
msg1.display(); // 输出fld2,fld3,fld4 Folder *fld5 = new Folder(fld2);
fld5->setName("fld5");
cout<<"message1 folder ..1"<<endl;
msg1.display(); // 输出fld2,fld3,fld4,fld5 delete fld5;
cout<<"message1 folder ..1"<<endl;
msg1.display(); // 输出fld2,fld3,fld4 fld2.remove(msg1);
cout<<"message1 folder ..1"<<endl;
msg1.display();

c++ Message与Folder 拷贝 析构(没有动态空间的类)的更多相关文章

  1. 关于实现Extjs动态加载类的方式实现

    Extjs4以前的版本没有动态加载类的方式,这样开发程序的时候加载很多的js会导致加载变慢,由于本人一直使用extjs3的版本进行开发,于是简单实现了一个动态加载类的管理器,使用方式与extjs4的方 ...

  2. winfrom之动态控件生成以及保存动态空间的数据

    前些天要完成一个winform程序,里面涉及到动态控件的添加以及保存动态空间中数据的保存,效果如下 初始化时: 点击添加阶梯价后:(点击一下,动态添加一行) 那么接下来,我们就具体的讲下代码实现: 首 ...

  3. tomcat 5.5 动态加载类

    转载于:http://www.itxuexiwang.com/a/javadianzishu/tomcat/2016/0225/161.html?1456480735 开发使用的是tomcat5.5. ...

  4. [javaSE] 反射-动态加载类

    Class.forName(“类的全称”) ①不仅表示了类的类类型,还代表了动态加载类 ②请大家区分编译,运行 ③编译时刻加载类是静态加载类,运行时刻加载类是动态加载类 Ⅰ所有的new对象都是静态加载 ...

  5. java动态加载类和静态加载类笔记

    JAVA中的静态加载类是编译时刻加载类  动态加载类指的是运行时刻加载类 二者有什么区别呢 举一个例子  现在我创建了一个类  实现的功能假设为通过传入的参数调用具体的类和方法 class offic ...

  6. Java动态加载类在功能模块开发中的作用

    Java中我们一般会使用new关键字实例化对象然后调用该对象所属类提供的方法来实现相应的功能,比如我们现在有个主类叫Web类这个类中能实现各种方法,比如用户注册.发送邮件等功能,代码如下: /* * ...

  7. java reflect 初始学习 动态加载类

    首先要理解Class类: 在java 的反射中,Class.forName("com.lilin.Office") 使用类的全名,这样获取,不仅仅表示了类的类类型,同时还代表着类的 ...

  8. Java基础---Java---基础加强---类加载器、委托机制、AOP、 动态代理技术、让动态生成的类成为目标类的代理、实现Spring可配置的AOP框架

    类加载器 Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader 类加载器也是Jav ...

  9. Java运行时动态加载类之ClassLoader

    https://blog.csdn.net/fjssharpsword/article/details/64922083 *************************************** ...

随机推荐

  1. Word2010制作收款单

    原文链接:https://www.toutiao.com/i6488255406136099342/ 页面设置 选择"页面布局"选项卡,"页面设置"功能组,&q ...

  2. SpringCloud的Config应用

    一.简介 ***应用程序先注册到注册中心,在注册中心根据guli-config服务的名字找到配置中心,然后在配置中心根据配置从github加载基本配置. 二.配置中心(服务端,可以部署集群) 1.依赖 ...

  3. nuxt 相关

    https://github.com/xuqiang521/nuxt-ssr-demo https://www.cnblogs.com/laozhang-is-phi/p/10249248.html ...

  4. XCTF(Web_php_unserialize)

    拿到题目,是个这, 我们来一波代码审计 1 <?php 2 class Demo { 3 private $file = 'index.php'; 4 public function __con ...

  5. vscode语法检查/智能代码失效

    问题 使用C++编写作业时候,智能代码提示是disturb什么,没注意就选了,结果没了编写代码时候的报错提示. 查找全局并没有发现关闭了代码语法检查. 找了半天,重装一次,发现原来在这里.工作空间单独 ...

  6. 切换不同的echarts时,出现图标缩小,报警告,Can’t get dom width or height!

    出现这样的原因是因为,在切换的时候,图表所对应的标签还没有显示出来,最好将代码放在$nextick里面执行,并且,采用使用v-if进行切换 转载:https://www.pianshen.com/ar ...

  7. gin中绑定uri

    package main import ( "github.com/gin-gonic/gin" "net/http" ) type Person struct ...

  8. ES6复习干货知识点汇总

    一.问:ES6是什么,为什么要学习它,不学习ES6会怎么样? 答: ES6是新一代的JS语言标准,对分JS语言核心内容做了升级优化,规范了JS使用标准,新增了JS原生方法,使得JS使用更加规范,更加优 ...

  9. 第06讲:Flink 集群安装部署和 HA 配置

    Flink系列文章 第01讲:Flink 的应用场景和架构模型 第02讲:Flink 入门程序 WordCount 和 SQL 实现 第03讲:Flink 的编程模型与其他框架比较 第04讲:Flin ...

  10. 安卓开发常见Bug-项目未升级到Androidx

    当项目未升级到androidx时,会出现某些项目文件资源不匹配的问题,建议在建立项目后就将项目升级到androidx 点击升级到androidx Migrate迁移然后点击左下角Dorefactor