条件
- 使用两个类设计,Message——表示电子邮件消息,Folder——表示消息目录。
- 每个Message可以出现在多个Folder中。
- 修改某一条Message,它在它所在的所有Folder中都会被修改。
- Message使用一个set保存它所在的Folder的Folder指针。Folder也会用set保存它包含的Message的Message指针。
- Message要有save和remove操作,向一个给定的Folder添加或删除一条Message。Folder也得有类似的操作。
- 拷贝一个Message,将会拷贝其消息内容和保存Folder指针的set。同时每个包含此消息的Folder都添加一个指向新创建的Message的指针;销毁一个Message时,也要从包含此Message的所有Folder中删除指向此Message的指针。
- 将一个Message赋予另一个Message时,左侧的Message会被右侧代替。同时更新Folder,将保存左侧Message的Folder中将它删除,然后添加右侧的Message
实现
框架
class Message
{
friend class Folders;
public:
explicit Message(const string &str = "") : contents(str) {}
Message(const Message&);
Message& operator=(const Message&);
~Message();
void save(Folder&);
void remove(Folder&);
private:
string contents;
set<Folder*> folders;
//将本Message添加到指向参数的Folder中
void add_to_Folders(const Message&);
//从folders中的每个Folder中删除本Message
void remove_from_Folders();
};
save和remove成员
void Message::save(Folder &f)
{
//添加到folders,表示这个Folder保存了本信息
folders.insert(&f);
//将本信息添加到f的Message集合中
f.addMsg(this);
}
void Message::remove(Folder &f)
{
folders.erase(&f);
f.remMsg(this);
}
拷贝控制成员
拷贝构造函数
拷贝一个Message,将会拷贝其消息内容和保存Folder指针的set。同时每个包含此消息的Folder都添加一个指向新创建的Message的指针
包含此消息的Folder们保存在folders中,所以如果拷贝一个Message,就要遍历该Message的folders,对其中每个Folder都要添加一个指向拷贝的新指针。拷贝构造函数和拷贝赋值运算符运算符都要完成这个工作,所以定一个一个函数完成这个公共工作(一般这种公共工作都是private的)
void add_to_Folders(const Message &m)
{
for (auto f : m.folders)
f->addMsg(this);
}
拷贝构造函数如下:
Message::Message(const Message &m) :
contents(m.contents), folders(m.folders)
{ add_to_Folders(m); }
析构函数
而当一个Message被销毁时,必须从所有指向此Message的Folder中删除它。拷贝赋值运算符也要做这个工作,所以还是定义一个private的函数:
void Message::remove_from_Folders()
{
for (auto f : folders)
f->remMsg(this);
}
tips:拷贝赋值运算符通常执行拷贝构造函数和析构函数中也要做的工作。这种情况下,公共的工作应该作为函数放在private中
同时就能定义析构函数:
Message::~Message() { remove_from_Folders(); }
拷贝赋值运算符
左侧的Message被右侧替代,就相当于左侧的Message被销毁(遍历左侧的folders,删除指向自己的Folder),然后拷贝为右侧的Message(遍历右侧的folders,添加指向拷贝的新指针)
Message& Message::operator=(const Message &rhs)
{
remove_from_Folders();
contents = rhs.contents;
folders = rhs.folders;
add_to_Folders(rhs);
return *this;
}
自己的Message和Folder类
- 实现了对应的Folder类
- 添加了addFldr()函数和rmvFldr()函数,分别实现向当前Message对象插入/删除一个Folder
class Folder
{
friend class Message;
public:
explicit Folder(const string &str = "") : title(str) {}
Folder(const Folder&);
Folder& operator=(const Folder&);
~Folder() { remove_from_Message(); }
private:
string title;
set<Message*> msgs;
void add_to_Message(const Folder &f)
{
for (auto m : f.msgs)
m->addFldr(this);
}
void remove_from_Message()
{
for (auto m : msgs)
m->rmvFldr(this);
}
void remMsg(Message *m) { msgs.erase(m); }
void addMsg(Message *m) { msgs.insert(m); }
};
Folder::Folder(const Folder &f) : title(f.title), msgs(f.msgs)
{
//拷贝构造新的Folder
//将老Folder消息集里的消息的set都添加上新Folder的指针
add_to_Message(f);
}
Folder& Folder::operator=(const Folder &f)
{
//拷贝赋值运算符函数,同时执行拷贝构造函数功能和析构函数功能
remove_from_Message();
title = f.title;
msgs = f.msgs;
add_to_Message(f);
return *this;
}
class Message
{
public:
explicit Message(const string &str = "") : contents(str) {}
Message(const Message &m) : contents(m.contents), folders(m.folders) { add_to_Folders(m); }
Message& operator=(const Message&);
~Message() { remove_from_Folders(); }
void saveTo(Folder &f)
{
folders.insert(&f);
f.addMsg(this);
}
void addFldr(Folder *f) { folders.insert(f); }
void removeFrom(Folder &f)
{
folders.erase(&f);
f.remMsg(this);
}
void rmvFldr(Folder *f) { folders.erase(f); }
private:
string contents;
set<Folder*> folders;
void add_to_Folders(const Message &m)
{
for (auto f : m.folders)
f->addMsg(this);
}
void remove_from_Folders()
{
for (auto f : folders)
f->remMsg(this);
}
};
Message& Message::operator=(const Message &rhs)
{
remove_from_Folders();
contents = rhs.contents;
folders = rhs.folders;
add_to_Folders(rhs);
return *this;
}
给Message类加上移动构造函数和移动赋值运算符
Message有string和contents和set的folders,如果用拷贝会比较耗时耗力,利用移动控制能避免产生额外开销。接管了旧Message的资源后就要更新folders,将旧Message换成接管了旧Message的新Message。用一个函数来实现这个操作:
void move_Folders(Message *m)
{
folders = std::move(m->folders); //调用set的移动赋值运算符
for (auto f : folders)
{
f->remMsg(m);
f->addMsg(this);
}
m->folders.clear();
//将老m置于可析构状态
//确保销毁m没有别的影响
}
class Message
{
public:
explicit Message(const string &str = "") : contents(str) {}
Message(const Message &m) : contents(m.contents), folders(m.folders) { add_to_Folders(m); }
//移动构造函数,因为是接管m,所以要从Floder中删除老的m,添加成新的接管了m的左侧对象
Message(Message &&m) : contens(std::move(m.contents)) { move_Folders(&m); }
Message& operator=(const Message &rhs)
{
remove_from_Folders();
contents = rhs.contents;
folders = rhs.folders;
add_to_Folders(rhs);
return *this;
}
//移动赋值运算符
Message& operator=(Message &rhs)
{
if (this != &rhs)
{
remove_from_Folders();
contents = std::move(rhs.contents);
move_Folders(&rhs);
}
return *this;
}
~Message() { remove_from_Folders(); }
void saveTo(Folder &f)
{
folders.insert(&f);
f.addMsg(this);
}
void addFldr(Folder *f) { folders.insert(f); }
void removeFrom(Folder &f)
{
folders.erase(&f);
f.remMsg(this);
}
void rmvFldr(Folder *f) { folders.erase(f); }
private:
string contents;
set<Folder*> folders;
void add_to_Folders(const Message &m)
{
for (auto f : m.folders)
f->addMsg(this);
}
void remove_from_Folders()
{
for (auto f : folders)
f->remMsg(this);
}
void Message::move_Folders(Message *m)
{
folders = std::move(m->folders); //调用set的移动赋值运算符
for (auto f : folders)
{
f->remMsg(m);
f->addMsg(this);
}
m->folders.clear();
//将老m置于可析构状态
}
};
Message& Message::operator=(const Message &rhs)
{
remove_from_Folders();
contents = rhs.contents;
folders = rhs.folders;
add_to_Folders(rhs);
return *this;
}