zoukankan      html  css  js  c++  java
  • c++ Message与Folder 拷贝 析构(没有动态空间的类)

    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();
    

  • 相关阅读:
    操作正则表达式的公共类
    验证码类
    强制转化常用函数
    实现Base64编码与其它编码转换的类
    关于任务管理器踩过的坑,程序员必看!
    每次找Internet选项感到抓狂?一键打开!
    教你避过安装TensorFlow的两个坑
    HTML中id与name的通俗区别
    VS code代码对齐快捷键
    form和table的区别
  • 原文地址:https://www.cnblogs.com/yuandonghua/p/15635949.html
Copyright © 2011-2022 走看看