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. Go语言系列之标准库ioutil

    ioutil标准库中提供了一些常用.方便的IO操作函数 一.相关方法 func ReadAll(r io.Reader) ([]byte, error) func ReadDir(dirname st ...

  2. vue js格式化数字为金额格式

    /** * @description 格式化金额 * @param number:要格式化的数字 * @param decimals:保留几位小数 默认0位 * @param decPoint:小数点 ...

  3. 使用.NET 6开发TodoList应用(29)——实现静态字符串本地化功能

    系列导航及源代码 使用.NET 6开发TodoList应用文章索引 需求 在开发一些需要支持多种语言的应用程序时,我们需要根据切换的语言来对应展示一些静态的字符串字段,在本文中我们暂时不去讨论如何结合 ...

  4. Java包装类和处理对象

    Java中基本类型变量和字符串之间的转换 public class Primitive2String { public static void main(String args[]) { String ...

  5. 【Java】GUI编程

    GUI编程 前言 某koukou老师的任务罢了,好在狂神老师居然有GUI的课,只能说是有救星了. [狂神说Java]GUI编程入门到游戏实战 最好笑的是,老师要求掌握的居然是14年的知识,就连狂神在上 ...

  6. Qt中编译器

    很多时候,Qt构建项目编译的过程中会报错,大部分报错是因为qt的设置出现问题,很多时候环境配置时要选择合适的编译器,debugger调试器等,这里对一些名词解释,内容对新手很友好,大佬就不用看啦. M ...

  7. How to check in Windows if you are using UEFI

    You might be wondering if Windows is using UEFI or the legacy BIOS, it's easy to check. Just fire up ...

  8. Webpack之 webpack-dev-server 中的 contentBase配置及作用

    contentBase:主要是指定静态资源的根目录的.  

  9. 布客&#183;ApacheCN 编程/后端/大数据/人工智能学习资源 2020.9

    公告 ApacheCN 项目的最终目标:五年内备份并翻译 Github 上的所有教程(其实快被我们啃完了,剩下的不多了). 警告各位培训班:对 ApacheCN 宣传文章的举报,也将视为对 Apach ...

  10. java的装箱和拆箱详解

    ========================================================================================= 在我看来,学习jav ...