C++ Primer 学习笔记_56_类与数据抽象 --消息处理示例(一)

2014-11-24 12:27:00 · 作者: · 浏览: 2

复制控制

--消息处理示例



说明:

有些类为了做一些工作需要对复制进行控制。为了给出这样的例子,我们将概略定义两个类,这两个类可用于邮件处理应用程序。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成员赋值