-
Notifications
You must be signed in to change notification settings - Fork 1
/
Exer13_34_36_37_Folder.h
180 lines (180 loc) · 5.54 KB
/
Exer13_34_36_37_Folder.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#ifndef MESSAGE_FOLDER_H
#define MESSAGE_FOLDER_H
#include <iostream>
#include <string>
#include <set>
class Folder; // incomplete class declaration
class Message {
friend class Folder;
friend void swap(Message&, Message&);
public:
// folders is implicitly initialized to the empty std::set
explicit Message(const std::string &str = "") : contents(str) {}
// copy control to manage pointers to this Message
Message(const Message&); // copy constructor
Message& operator=(const Message&); // copy assignment
~Message(); // destructor
// add/remove this Message from the specified Folder's std::set of messages
void save(Folder&);
void remove(Folder&);
// insert or remove a given Folder* into folders, required by exercise 13.37
void addFolder(Folder*);
void remFolder(Folder*);
private:
std::string contents; // actual message text
std::set<Folder*> folders; // Folders that have this Message
// utility functions used by copy constructor, copy-assignment operator and destructor
// add this Message to the Folders that point to the parameter
void add_to_Folders(const Message&);
// remove this Message from every Folder in folders
void remove_from_Folders();
};
class Folder {
friend void swap(Folder&, Folder&);
public:
explicit Folder(const std::string &s = "") : name(s) {}
Folder(const Folder&);
Folder& operator=(const Folder&);
~Folder();
void addMsg(Message*);
void remMsg(Message*);
void show();
private:
std::string name;
std::set<Message*> messages;
void add_messages(const Folder&);
void remove_messages();
};
void Folder::addMsg(Message *m)
{
messages.insert(m);
// m->folders.insert(this);
}
void Folder::remMsg(Message *m)
{
messages.erase(m);
// m->folders.erase(this);
}
void Folder::show()
{
for(auto m : messages)
std::cout << m->contents << std::endl;
}
void Message::save(Folder &f)
{
folders.insert(&f); // add the given Folder to our list of Folders
f.addMsg(this); // add this Message to f's std::set of Messages
}
void Message::remove(Folder &f)
{
folders.erase(&f); // take the give Folder out of our list of Folders
f.remMsg(this); // remove this Message to f's std::set of Messages
}
// add this Message to Folders that point to m
void Message::add_to_Folders(const Message &m)
{
for(auto f : m.folders) // for each Folder that holds m
f->addMsg(this); // add a pointer to this Message to that folders
}
// remove this message from the corresponding Folders
void Message::remove_from_Folders()
{
for(auto f : folders) // for each pointer in folders
f->remMsg(this); // remove this Message from that Folder
}
// copy constructor
Message::Message(const Message &m) : contents(m.contents), folders(m.folders)
{
add_to_Folders(m); // add this Message to the Folders that point to m
}
// destructor
Message::~Message()
{
remove_from_Folders();
}
// copy-assignment operator
Message& Message::operator=(const Message& rhs)
{
// handle self-assignment by removing pointers before inserting them
remove_from_Folders(); // update existing Folders
contents = rhs.contents; // copy message contents from rhs
folders = rhs.folders; // copy Folder pointers from rhs
add_to_Folders(rhs); // add this Message to those Folders
return *this;
}
// swap function
void swap(Message &lhs, Message &rhs)
{
using std::swap; // not strictly needed in this case, but good habit
for(auto f : lhs.folders)
f->remMsg(&lhs);
for(auto f : rhs.folders)
f->remMsg(&rhs);
// swap the contents and Folder pointer sets
swap(lhs.folders, rhs.folders); // use swap(std::set&, std::set&)
swap(lhs.contents, rhs.contents); // swap(std::string&, std::string&)
// add pointer to each Message to their (new) respective Folders
for(auto f : lhs.folders)
f->addMsg(&lhs);
for(auto f : rhs.folders)
f->remMsg(&rhs);
}
void Message::addFolder(Folder *f)
{
folders.insert(f);
}
void Message::remFolder(Folder *f)
{
folders.erase(f);
}
void Folder::add_messages(const Folder &f)
{
for(auto m : f.messages)
m->save(*this);
}
void Folder::remove_messages()
{
for(auto m : messages)
m->remove(*this);
messages.clear(); // clear the messages because no message points to this folder
}
Folder::Folder(const Folder &f) : name(f.name), messages(f.messages)
{
add_messages(f);
}
Folder& Folder::operator=(const Folder &rhs)
{
remove_messages();
name = rhs.name;
messages = rhs.messages;
add_messages(rhs);
return *this;
}
Folder::~Folder()
{
remove_messages();
}
void swap(Folder &lhs, Folder &rhs)
{
using std::swap;
for(auto m : lhs.messages)
m->remove(lhs);
for(auto m : rhs.messages)
m->remove(rhs);
swap(lhs.name, rhs.name);
swap(lhs.messages, rhs.messages);
for(auto m : lhs.messages)
m->save(lhs);
for(auto m : rhs.messages)
m->save(rhs);
}
#endif
// Note: should we add a pointer in folders of Message class in the member
// function addMsg of Folder? Practically, this will induce loop call: addMsg
// calls save, save calls addMsg. Conceptually, this contrasts to the feature of
// each class. Every class just takes response of its own. It shouldn't
// interfere with other class' operation. In fact, Folder shouldn't know how
// Message processes its data. On the other hand, we cannot only use addMsg
// outside both classes. This way a folder has pointed to a message, but a
// message doesn't know this. Because we didn't add a record in folder of that
// message.