在本片文章中,我们将概述两个类的设计,这两个类可以用于邮件处理应用中。(消息处理示例)
提供两个类名Message和Folder,分别表示一种类型的消息和消息目录。每个Message对象可以出现在多个Folder中。但是任意给定的Message的内容只有一个副本。这样,如果一条Message的内容被改变,则我们从他所在的任何Folder来浏览此Message时,都会看到改变后的内容。
为了记录Message位于哪些Folder中,每个Message都会保存一个它所在Folder的指针的set。同样的每个Folder都保存一个它包含的Message的指针set。
Message类:
#pragma once
#include<string>
#include<set>
using namespace std;
class Message {
friend class Folder;
public:
explicit Message(const string &str = "") :
contents(str) {}
Message(const Message&);
Message& operator=(const Message&);
~Message();
void addFldr(Folder *); //添加给定的Folder
void remFldr(Folder *); //删除给定的Folder
//从给定的Folder集合中添加、删除Message
void save(Folder&);
void remove(Folder&);
private:
string contents; //实际消息文本
set<Folder*>folders; //包含本Message的Folder
//拷贝构造函数、拷贝赋值运算符和析构函数所使用的工具函数
//将本Message添加到指向参数的Folder中
void add_to_Folders(const Message&);
//从folders中的每个Folder中删除本Message
void remove_from_Folders();
};
上述中提供了save和remove操作,来向一个给定Folder添加一条Message或是从中删除一条Message。
void Message::save(Folder &f)
{
folders.insert(&f); //将给定的folder添加到我们的Folder列表中
f.addMsg(this); //将Message添加到f的Message集合中
}
void Message::remove(Folder &f)
{
folders.erase(&f); //将给定Folder 从我们的Folder列表中删除
f.remMsg(this); //将Message从f的Message集合中删除
}
当我们拷贝一个Message时,副本和原对象将是不同的Message对象,但两个Message都出现在相同的Folder中。因此,拷贝Message的操作包括消息内容的拷贝和Folder指针set的拷贝。并且我们必须在每个包含此消息的Folder中都添加一个指向新创建的Message指针。
void Message::add_to_Folders(const Message &m)
{
for (auto f : m.folders) //对于每个包含m的Folder,向该Folder添加一个指向本Message的指针
f->addMsg(this);
}
Message::Message(const Message &m):
contents(m.contents),folders(m.folders)
{
add_to_Folders(m);
}
但我们销毁一个Message时,它将不复存在,所以我们必须在,包含此Message的Folder中删除指向此消息的指针。
对于拷贝构造函数和析构函数的说明,如果我们使用合成的版本,可以简单的实现拷贝每个数据成员或销毁。但是当我们拷贝一个Message时不仅要拷贝,还要将此消息添加到对应的Folder中(调用addMsg)。同理,当销毁时,需要从他所在的Folders中删除(调用remMsg)。
void Message::remove_from_Folders()
{
for (auto f : folders)
f->remMsg(this); //对folders中的每个指针,从该Folder中删除本Message
}
Message::~Message()
{
remove_from_Folders();
}
当我们讲一个Message对象赋予另一个对象时,左侧Message的内容会被右侧Message的内容所代替。并且此时,我们必须更新Folder集合,从原来包含左侧Message的Folder中将它删除,并将它添加到包含右侧消息的Folder中。
Message &Message::operator=(const Message &rhs)
{
//通过先删除指针再插入它们,来处理自赋值的情况
remove_from_Folders();
contents = rhs.contents;
folders = rhs.folders;
add_to_Folders(rhs);
return *this;
}
对于Message另外两个成员函数添加给定的Folder和删除给定的Folder,定义如下:
void Message::addFldr(Folder*f)
{
folders.insert(f);
}
void Message::remFldr(Folder*f)
{
folders.erase(f);
}
对于Folder类的定义如下:
#pragma once
#include"Message.h"
class Folder {
public:
void addMsg(Message *m) { msgs.insert(m); }
void remMsg(Message *m) { msgs.erase(m); }
Folder(const Folder&);
Folder& operator=(const Folder&);
~Folder();
private:
set<Message*> msgs;
void add_to_Message(const Folder&); //将这个Folder添加到所有的Message中
void remove_from_Msgs(); //把这个Folder从所有的Message中删除
};
首先实现了Message类用到的两个函数,将消息添加和删除文件夹。此外,Folder也应该有将自身添加到和删除出所有的Message的foldes集合中的成员函数,定义如下:
void Folder::add_to_Message(const Folder &f)
{
for (auto msg : f.msgs)
msg->addFldr(this);
}
void Folder::remove_from_Msgs()
{
while (!msgs.empty())
{
(*msgs.begin())->remove(*this);
}
}
对于Folder的拷贝构造函数,它首先拷贝msgs集合,然后调用add_to_Message将其添加到它所有的Message的folders集合中。
Folder::Folder(const Folder &f) :msgs(f.msgs)
{
add_to_Message(f);
}
析构函数调用remove_from_Msgs从所有Message中删除本Folder
Folder::~Folder()
{
remove_from_Msgs();
}
拷贝赋值运算符首先将Folder从每个旧的Message中删除,然后从右侧Folder拷贝Message集合,最后将自身添加到每个新Message中。
Folder& Folder::operator=(const Folder&f)
{
remove_from_Msgs();
msgs = f.msgs;
add_to_Message(f);
return *this;
}
综合代码如下:
Message类的定义
#pragma once
#include<string>
#include<set>
using namespace std;
class Message {
friend class Folder;
public:
explicit Message(const string &str = "") :
contents(str) {}
Message(const Message&);
Message& operator=(const Message&);
~Message();
void addFldr(Folder *); //添加给定的Folder
void remFldr(Folder *); //删除给定的Folder
//从给定的Folder集合中添加、删除Message
void save(Folder&);
void remove(Folder&);
void show();
private:
string contents; //实际消息文本
set<Folder*>folders; //包含本Message的Folder
//拷贝构造函数、拷贝赋值运算符和析构函数所使用的工具函数
//将本Message添加到指向参数的Folder中
void add_to_Folders(const Message&);
//从folders中的每个Folder中删除本Message
void remove_from_Folders();
};
Message类的成员函数定义
#include"Folder.h"
#include"Message.h"
void Message::addFldr(Folder*f)
{
folders.insert(f);
}
void Message::remFldr(Folder*f)
{
folders.erase(f);
}
void Message::save(Folder &f)
{
folders.insert(&f); //将给定的folder添加到我们的Folder列表中
f.addMsg(this); //将Message添加到f的Message集合中
}
void Message::remove(Folder &f)
{
folders.erase(&f); //将给定Folder 从我们的Folder列表中删除
f.remMsg(this); //将Message从f的Message集合中删除
}
void Message::add_to_Folders(const Message &m)
{
for (auto f : m.folders) //对于每个包含m的Folder,向该Folder添加一个指向本Message的指针
f->addMsg(this);
}
Message::Message(const Message &m):
contents(m.contents),folders(m.folders)
{
add_to_Folders(m);
}
void Message::remove_from_Folders()
{
for (auto f : folders)
f->remMsg(this); //对folders中的每个指针,从该Folder中删除本Message
}
Message::~Message()
{
remove_from_Folders();
}
Message &Message::operator=(const Message &rhs)
{
remove_from_Folders();
contents = rhs.contents;
folders = rhs.folders;
add_to_Folders(rhs);
return *this;
}
void Message::show()
{
cout << "folders的个数有:" << folders.size() << endl;
}
Folder类的定义:
#pragma once
#include"Message.h"
class Folder {
public:
void addMsg(Message *m) { msgs.insert(m); }
void remMsg(Message *m) { msgs.erase(m); }
Folder(const Folder&);
Folder& operator=(const Folder&);
~Folder();
void show();
private:
set<Message*> msgs;
void add_to_Message(const Folder&); //将这个Folder添加到所有的Message中
void remove_from_Msgs(); //把这个Folder从所有的Message中删除
};
Folder类的成员函数的定义
#include"Folder.h"
#include"Message.h"
void Folder::add_to_Message(const Folder &f)
{
for (auto msg : f.msgs)
msg->addFldr(this);
}
void Folder::remove_from_Msgs()
{
while (!msgs.empty())
{
(*msgs.begin())->remove(*this);
}
}
Folder::Folder(const Folder &f) :msgs(f.msgs)
{
add_to_Message(f);
}
Folder::~Folder()
{
remove_from_Msgs();
}
Folder& Folder::operator=(const Folder&f)
{
remove_from_Msgs();
msgs = f.msgs;
add_to_Message(f);
return *this;
}
void Folder::show()
{
cout << "msgs的个数有:" << msgs.size() << endl;
}
最后写一个样例测试一下:
#include"Folder.h"
#include"Message.h"
#include<iostream>
int main()
{
string s1("hello1");
string s2("hello2");
string s3("hello3");
string s4("hello4");
string s5("hello5");
string s6("hello6");
// all new messages, no copies yet
Message m1(s1);
Message m2(s2);
Message m3(s3);
Message m4(s4);
Message m5(s5);
Message m6(s6);
Folder f1;
Folder f2;
m1.save(f1); m3.save(f1); m5.save(f1);
m1.save(f2);
m2.save(f2); m4.save(f2); m6.save(f2);
cout << "m1到m6中folders的个数:" << endl;
m1.show(); m2.show(); m3.show();
m4.show(); m5.show(); m6.show();
cout << endl;
cout << "f1到f2中Message的个数:" << endl;
f1.show(); f2.show();
cout << endl;
// create some copies
Message c1(m1);
Message c2(m2), c4(m4), c6(m6);
cout << "after create some copies: " << endl;
cout << "m1到m6中folders的个数:" << endl;
m1.show(); m2.show(); m3.show();
m4.show(); m5.show(); m6.show();
cout << endl;
cout << "f1到f2中Message的个数:" << endl;
f1.show(); f2.show();
cout << endl;
cout << "c1,c2,c4,c6中folders的个数:" << endl;
c1.show(); c2.show();
c4.show(); c6.show();
cout << endl;
// now some assignments
m2 = m3;
m4 = m5;
m6 = m3;
m1 = m5;
cout << "after some assignments: " << endl;
cout << "m1到m6中folders的个数:" << endl;
m1.show(); m2.show(); m3.show();
m4.show(); m5.show(); m6.show();
cout << endl;
cout << "f1到f3中Message的个数:" << endl;
f1.show(); f2.show();
cout << endl;
cout << "c1,c2,c4,c6中folders的个数:" << endl;
c1.show(); c2.show();
c4.show(); c6.show();
getchar();
}
结果如下: