码迷,mamicode.com
首页 > 其他好文 > 详细

复制控制(下)

时间:2016-02-24 19:01:25      阅读:143      评论:0      收藏:0      [点我收藏+]

标签:

  • 消息处理示例

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

技术分享

创建新的 Message 时,将指定消息的内容但不指定 Folder。调用 saveMessage 放入一个 Folder;复制一个 Message 对象时,将复制原始消息的内容和 Folder 指针集,还必须给指向源 Message 的每个 Folder 增加一个指向该 Message 的指针;将一个 Message 对象赋值给另一个,类似于复制一个 Message:赋值之后,内容和 Folder 集将是相同的。首先从左边 Message 在赋值之前所处的 Folder 中删除该 Message。原来的 Message 去掉之后,再将右边操作数的内容和 Folders 集复制到左边,还必须在这个 Folder 集中的每个 Folders 中增加一个指向左边 Message 的指针;撤销一个 Message 对象时,必须更新指向该 Message 的每个 Folder。一旦去掉了 Message,指向该 Message 的指针将失效,所以必须从该 MessageFolder 指针集的每个 Folder 中删除这个指针。//复制(复制构造函数)用来初始化一个空对象,赋值(赋值操作符)则是用来改变已经有内容(已被初始化过的)的对象为新内容。查看这个操作列表,可以看到,析构函数和赋值操作符分担了从保存给定 MessageFolder 列表中删除消息的工作。类似地,复制构造函数和赋值操作符分担将一个 Message 加到给定 Folder 列表的工作。我们将定义一对 private 实用函数完成这些任务。

  • Message Class
class Message {
     public:
         // folders is initialized to the empty set automatically
         Message(const std::string &str = ""):
                       contents (str) { }
         // copy control: we must manage pointers to this Message
         // from the Folders pointed to by folders
         Message(const Message&);//复制构造函数
         Message& operator=(const Message&);
         ~Message();
         // add/remove this Message from specified Folder‘s set of messages
         void save (Folder&);
         void remove(Folder&);
     private:
         std::string contents;      // actual message text
         std::set<Folder*> folders; // Folders that have this Message
         // Utility functions used by copy constructor, assignment, and destructor:
         // Add this Message to the Folders that point to the parameter
         void put_Msg_in_Folders(const std::set<Folder*>&);
         // remove this Message from every Folder in folders
         void remove_Msg_from_Folders();
     };

Message 类定义了两个数据成员:contents 是一个保存实际消息的 stringfolders 是一个 set,包含指向该 Message 所在的 Folder 的指针。构造函数接受单个 string 形参,表示消息的内容。构造函数将消息的副本保存在 contents 中,并(隐式)将 Folderset 初始化为空集。这个构造函数提供一个默认实参(为空串),所以它也可以作为默认构造函数。put_Msg_in_Folders 函数将自身 Message 的一个副本添加到指向给定 Message 的各 Folder 中,这个函数执行完后,形参指向的每个 Folder 也将指向这个 Message。复制构造函数和赋值操作符都将使用这个函数。remove_Msg_from_Folders 函数用于赋值操作符和析构函数,它从 folders 成员的每个 Folder 中删除指向这个 Message 的指针。

  • Message类的复制控制

复制 Message 时,必须将新创建的 Message 添加到保存原 Message 的每个 Folder 中。这个工作超出了合成构造函数的能力范围,所以我们必须定义自己的复制构造函数:

Message::Message(const Message &m):
         contents(m.contents), folders(m.folders)
     {
         // add this Message to each Folder that points to m
         put_Msg_in_Folders(folders);
     }

复制构造函数将用旧对象成员的副本初始化新对象的数据成员。除了这些初始化之外(合成复制构造函数可以完成这些初始化),还必须用 folders 进行迭代,将这个新的 Message 加到那个集的每个 Folder 中。复制构造函数使用 put_Msg_in_Folder 函数完成这个工作。编写自己的复制构造函数时,必须显式复制需要复制的任意成员。显式定义的复制构造函数不会进行任何自动复制。像其他任何构造函数一样,如果没有初始化某个类成员,则那个成员用该成员的默认构造函数初始化。复制构造函数中的默认初始化不会使用成员的复制构造函数。

  • put_Msg_in_Folders成员

put_Msg_in_Folders 通过形参 rhs 的成员 folders 中的指针进行迭代。这些指针表示指向 rhs 的每个 Folder,需要将指向这个 Message 的指针加到每个 Folder。函数通过 rhs.folders 进行循环,调用命名为 addMsgFolder 成员来完成这个工作,addMsg 函数将指向该 Message 的指针加到 Folder 中。

// add this Message to Folders that point to rhs
     void Message::put_Msg_in_Folders(const set<Folder*> &rhs)
     {
         for(std::set<Folder*>::const_iterator beg = rhs.begin();
                                          beg != rhs.end(); ++beg)
             (*beg)->addMsg(this);     // *beg points to a Folder
     }

这个函数中唯一复杂的部分是对 addMsg 的调用:

(*beg)->addMsg(this); // *beg points to a Folder

那个调用以 (*beg) 开关,它解除迭代器引用。解除迭代器引用将获得一个指向 Folder 的指针。然后表达式对 Folder 指针应用箭头操作符以执行 addMsg 操作,将 this 传给 addMsg,该指针指向我们想要添加到 Folder 中的 Message

  • Message赋值操作符

赋值比复制构造函数更复杂。像复制构造函数一样,赋值必须对 contents 赋值并更新 folders 使之与右操作数的 folders 相匹配。它还必须将该 Message 加到指向 rhs 的每个 Folder 中,可以使用 put_Msg_in_Folders 函数完成赋值的这一部分工作。在从 rhs 复制之前,必须首先从当前指向该 Message 的每个 Folder 中删除它。我们需要通过 folders 进行迭代,从 folders 的每个 Folder 中删除指向该 Message 的指针。命名为 remove_Msg_from_Folders 的函数将完成这项工作。对于完成实际工作的 remove_Msg_from_Foldersput_Msg_in_Folders,赋值操作符本身相当简单:

Message& Message::operator=(const Message &rhs)
     {
         if (&rhs != this) {
             remove_Msg_from_Folders(); // update existing Folders
             contents = rhs.contents;   // copy contents from rhs
             folders = rhs.folders;     // copy Folder pointers from rhs
             // add this Message to each Folder in rhs
             put_Msg_in_Folders(rhs.folders);
         }
         return *this;
     }

赋值操作符首先检查左右操作数是否相同。查看函数的后续部分可以清楚地看到进行这一检查的原因。假定操作数是不同对象,调用 remove_Msg_from_Foldersfolders 成员的每个 Folder 中删除该 Message。一旦这项工作完成,必须将右操作数的 contentsfolders 成员赋值给这个对象。最后,调用 put_Msg_in_Folders 将指向这个 Message 的指针添加至指向 rhs 的每个 Folder 中。了解了 remove_Msg_from_Folders 的工作之后,我们来看看为什么赋值操作符首先要检查对象是否不同。赋值时需删除左操作数,并在撤销左操作数的成员之后,将右操作数的成员赋值给左操作数的相应成员。如果对象是相同的,则撤销左操作数的成员也将撤销右操作数的成员!即使对象赋值给自己,赋值操作符的正确工作也非常重要。保证这个行为的通用方法是显式检查对自身的赋值。

  • remove_Msg_from_Folders成员

除了调用 remMsgfolders 指向的每个 Folder 中删除这个 Message 之外,remove_Msg_from_Folders 函数的实现与 put_Msg_in_Folders 类似:

// remove this Message from corresponding Folders
     void Message::remove_Msg_from_Folders()
     {
         // remove this message from corresponding folders
         for(std::set<Folder*>::const_iterator beg =
               folders.begin (); beg != folders.end (); ++beg)
            (*beg)->remMsg(this); // *beg points to a Folder
     }
  • Message析构函数

剩下必须实现的复制控制函数是析构函数:

Message::~Message()
     {
         remove_Msg_from_Folders();
     }

有了 remove_Msg_from_Folders 函数,编写析构函数将非常简单。我们调用 remove_Msg_from_Folders 函数清除 folders,系统自动调用 string 析构函数释放 contents,自动调用 set 析构函数清除用于保存 folders 成员的内存,因此,Message 析构函数唯一要做的是调用 remove_Msg_from_Folders。赋值操作符通常要做复制构造函数和析构函数也要完成的工作。在这种情况下,通用工作应在 private 实用函数中。

 

 

 

 

复制控制(下)

标签:

原文地址:http://www.cnblogs.com/predator-wang/p/5213711.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!