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 
#include 
#include 

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 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 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中的set表
void Message::save(Folder &f) {
    folders.insert(&f);            // 更新set表,指示这条message存在某个Folder中。
    f.messages.insert(this);    // 更新set表,指示folder中有这条消息。
}

// 将message(this)从某个Folder中去除
// 这里要更新message(this)的set表和Folder中的set表
void Message::remove(Folder &f) {
    folders.erase(&f);
    f.messages.erase(this);
}

// Message在拷贝和析构操作的时候,会复制一条message,或者销毁一条message
// message复制和销毁要同步更新这条message存在的folder的set表
// 复制消息的时候,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表
// 左侧对象被右侧对象覆盖,左侧对象的set也被覆盖,这样要根据拷贝的set更新Folder中的set表
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() {
    update_folder_set(REMOVE);
}


// Message的交换函数
// 理论上是在vector调用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<getName()<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"<setContents("msg5");
cout<<"folder messages ..4"<setName("fld5");
cout<<"message1 folder ..1"<

相关