拷贝控制示例包含两个对象Message和Folder,类似于邮件中一个Message和文件夹Folder的关系:一个Message隶属于一个和多个Folder,一个Folder中包含0个或者多个Message。
这样看来,Message和Folder的关系,可以认为是等价的(忽略Folder的0对多)。他们之间的关系操作,包括如下几个:
- 拷贝操作:拷贝后副本与源独立,副本拥有源的所有内容和包含关系,并需要在所有关联的对象中建立关联
- 销毁操作:从与之关联的对象中,删除与本对象的关系
- 增加关系(save):添加一条新的关联
- 删除关系(remove):删除一条关系
class Message { friend class Folder; public: explicit Message(const std::string &str = "") :contents(str) { } Message(const Message& msg) :contents(msg.contents), folders(folders) { add_to_Folders(msg); } //如果使用拷贝并交换方式会增加两个私有函数的调用次数 Message& operator=(const Message& msg) { remove_from_Folders();//先删除Folder中存储的msg引用 contents = msg.contents; folders = msg.folders; add_to_Folders(msg);//再将folders记录中的folder中添加msg return *this; } ~Message() { remove_from_Folders(); } void swap(Message &lhs, Message &rhs) { using std::swap; for (auto f : lhs.folders) f->remove(lhs); for (auto f : rhs.folders) f->remove(rhs); swap(lhs.folders, rhs.folders); swap(lhs.contents, rhs.contents); for (auto f : lhs.folders) f->save(lhs); for (auto f : rhs.folders) f->save(rhs); } void save(Folder& f) { folders.insert(&f); f.save(*this); } void remove(Folder&f) { folders.erase(&f); f.remove(*this); } private: string contents; set<Folder*> folders; void add_to_Folders(const Message& msg) { for (auto f : msg.folders) f->save(*this); } void remove_from_Folders() { for (auto f : this->folders) f->remove(*this); } }; class Folder { friend class Message; public: explicit Folder(const std::string &str = "") :folder_name(str) { } Folder(const Folder& folder) :folder_name(folder.folder_name), messages(messages) { add_to_Messages(folder); } //如果使用拷贝并交换方式会增加两个私有函数的调用次数 Folder& operator=(const Folder& folder) { remove_from_Messages();//先删除Folder中存储的msg引用 folder_name = folder.folder_name; messages = folder.messages; add_to_Messages(folder);//再将folders记录中的folder中添加msg return *this; } ~Folder() { remove_from_Messages(); } void swap(Folder &lhs, Folder &rhs) { using std::swap; for (auto f : lhs.messages) f->remove(lhs); for (auto f : rhs.messages) f->remove(rhs); swap(lhs.messages, rhs.messages); swap(lhs.folder_name, rhs.folder_name); for (auto f : lhs.messages) f->save(lhs); for (auto f : rhs.messages) f->save(rhs); } void save(Message& msg) { messages.insert(&msg); msg.save(*this); } void remove(Message& msg) { messages.erase(&msg); msg.remove(*this); } private: string folder_name; set<Message*> messages; void add_to_Messages(const Folder& folder) { for (auto f : folder.messages) f->save(*this); } void remove_from_Messages() { for (auto f : this->messages) f->remove(*this); } };