复制控制
--消息处理示例
说明:
有些类为了做一些工作需要对复制进行控制。为了给出这样的例子,我们将概略定义两个类,这两个类可用于邮件处理应用程序。Message类和 Folder类分别表示电子邮件(或其他)消息和消息所出现的目录,一个给定消息可以出现在多个目录中。Message上有 save和 remove操作,用于在指定Folder中保存或删除该消息。
数据结构:
对每个Message,我们并不是在每个Folder中都存放一个副本,而是使每个Message保存一个指针集(set),set中的指针指向该Message所在的Folder。每个Folder也保存着一些指针,指向它所包含的Message。数据结构如图所示。

操作:
创建新的Message时,将指定消息的内容但不指定Folder。调用save将 Message放入一个Folder。
复制一个Message对象时,将复制原始消息的内容和Folder指针集,还必须给指向源 Message的每个Folder增加一个指向该Message的指针。
将一个Message对象赋值给另一个,类似于复制一个Message:赋值之后,内容和 Folder集将是相同的。首先从左边Message在赋值之前所处的Folder中删除该Message。原来的Message去掉之后,再将右边操作数的内容和Folders集复制到左边,还必须在这个Folder集中的每个Folders中增加一个指向左边Message的指针。
撤销一个Message对象时,必须更新指向该Message的每个 Folder。一旦去掉了 Message,指向该Message的指针将失效,所以必须从该Message的Folder指针集的每个Folder中删除这个指针。
可以看到,析构函数和赋值操作符分担了从保存给定Message的 Folder列表中删除消息的工作。类似地,复制构造函数和赋值操作符分担将一个Message加到给定Folder列表的工作。我们将定义一对private实用函数完成这些任务。
实现:
1、Message类
class Message
{
public:
Message(const std::string &str = ""):contents(str){};
Message(const Message &);
Message &operator=(const Message &);
~Message();
void save(Folder &);
void remove(Folder &);
private:
std::string contents;
std::set
folders;
void put_Msg_in_Folders(const std::set
&); void remove_Msg_from_Folders(); };
put_Msg_in_Folders函数将自身Message的一个副本添加到指向给定Message的各Folder中,这个函数执行完后,形参指向的每个Folder也将指向这个Message。复制构造函数和赋值操作符都将使用这个函数。
remove_Msg_from_Folders函数用于赋值操作符和析构函数,它从folders成员的每个Folder中删除指向这个Message的指针。
2、Message类的复制控制
复制Message时,必须将新创建的Message添加到保存原Message的每 个 Folder中。这个工作超出了合成构造函数的能力范围,所以我们必须定义自己的复制构造函数:
Message::Message(const Message &m):
contents(m.contents),folders(m.folders)
{
put_Msg_in_Folders(folders);
}
复制构造函数将用旧对象成员的副本初始化新对象的数据成员。除了这些初始化之外(合成复制构造函数可以完成这些初始化),还必须用folders进行迭代,将这个新的Message加到那个集的每个Folder中。复制构造函数使用put_Msg_in_Folder函数完成这个工作。
编写自己的复制构造函数时,必须显式复制需要复制的任意成员。显式定义的复制构造函数不会进行任何自动复制。
像其他任何构造函数一样,如果没有初始化某个类成员,则那个成员用该成员的默认构造函数初始化。复制构造函数中的默认初始化不会使用成员的复制构造函数。
3、put_Msg_in_Folder成员
put_Msg_in_Folders通过形参 rhs的成员 folders中的指针进行迭代。这些指针表示指向rhs的每个Folder,需要将指向这个Message的指针加到每个Folder。
函数通过rhs.folders进行循环,调用命名为addMsg的 Folder成员来完成这个工作,addMsg函数将指向该Message的指针加到Folder中。
void Message::put_Msg_in_Folders(const set&rhs) { for (set ::const_iterator beg = rhs.begin(); beg != rhs.end(); ++beg) { /* *(*beg)解除迭代器引用。解除迭代器引用将获得一个指向 Folder 的指针 *然后表达式对 Folder 指针应用箭头操作符以执行addMsg 操作 *将 this 传给 addMsg,该指针指向我们想要添加到 Folder 中的Message */ (*beg) -> addMsg(this); } }
4、Message赋值操作符
赋值比复制构造函数更复杂。像复制构造函数一样,赋值必须对contents赋值并更新folders使之与右操作数的folders相匹配。它还必须将该Message加到指向rhs的每个 Folder中,可以使用put_Msg_in_Folders函数完成赋值的这一部分工作【但是需要注意的是函数的实参此时由folders换成了rhs.folders了】。
在从rhs复制之前,必须首先从当前指向该Message的每个Folder中删除它。我们需要通过folders进行迭代,从folders的每个Folder中删除指向该Message的指针。命名为remove_Msg_from_Folders的函数将完成这项工作。
对于完成实际工作的remove_Msg_from_Folders和put_Msg_in_Folders,赋值操作符本身相当简单:
Message &Message::operator=(const Message &rhs)
{
if (&rhs != this)
{
remove_Msg_from_Folders();
contents = rhs.contents;
folders = rhs.folders;
put_Msg_in_Folders(rhs.folders);
}
return *this;
}
假定操作数是不同对象,调用remove_Msg_from_Folders从 folders成员的每个Folder中删除该Message。一旦这项工作完成,必须将右操作数的contents和 folders成员赋值