Copy control-message processing example
Note:
Some Classes need to control replication to do some work. To give an example like this, we will roughly define two classes that can be used in mail processing applications. The Message class and the Folder class indicate the directories in which the email (or other) messages and messages appear. A given Message can appear in multiple directories. There are save and remove operations on the Message, which are used to save or delete the Message in the specified Folder.
Data structure:
For each Message, we do not store a copy in each Folder, but makeEachMessageSave a pointer set(Set), setThe pointer inMessageLocationFolder. EachFolderSome pointers are also saved.,Point toMessage.Data structure.
Operation:
When a new Message is created, the Message content is specified but the Folder is not specified. Call save to put the Message into a Folder.
When copying a Message object, the content of the original Message and the Folder pointer set will be copied, and a pointer pointing to the Message must be added to each Folder of the source Message.
Assign a Message object to another object, similar to copying a Message: After the value is assigned, the content will be the same as the Folder set. First, delete the Message from the left Message in the Folder before the value assignment. After the original Message is removed, copy the content of the right operand and the Folders set to the left, and add a pointer to the left Message in each Folders of the Folder set.
When revoking a Message object, each Folder pointing to the Message must be updated. Once the Message is removed, the pointer pointing to the Message becomes invalid. Therefore, you must delete the pointer from each Folder in the Folder pointer set of the Message.
As you can see, The Destructor and the value assignment operator share the work of deleting messages from the Folder list that saves the given Message. Similarly, the copy constructor and the value assignment operator share the work of adding a Message to the given Folder list. We will define a pair of private utility functions to complete these tasks.
Implementation:
1. Message class
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();};
The put_Msg_in_Folders function adds a copy of its own Message to the Folder pointing to the given Message. After this function is executed, each Folder pointing to the form parameter will also point to the Message. Both the copy constructor and the value assignment operator use this function.
The remove_Msg_from_Folders function is used to assign values to operators and destructor. It deletes the pointer to this Message from each Folder of the folders member.
2. Message replication Control
When copying a Message, you must add the newly created Message to each Folder that saves the original Message. This work is beyond the ability to synthesize constructor, so we must define our own copy constructor:
Message::Message(const Message &m): contents(m.contents),folders(m.folders){ put_Msg_in_Folders(folders);}
The copy constructor uses a copy of the old object member to initialize the data member of the new object. In addition to the initialization (The composite replication constructor can complete these initialization tasks.), You must also use folders to iterate and add the new Message to each Folder of the set. The copy constructor uses the put_Msg_in_Folder function to complete this task.
When writing your own copy constructor, you must explicitly copy any member to be copied.Explicit definitionThe replication constructor does not perform anyAuto copy.
Like any other constructor, if a class member is not initialized, the Member is initialized using the default constructor of the member. Default initialization in the copy constructorDo not use Member copy constructor.
3. put_Msg_in_Folder Member
Put_Msg_in_Folders iterates through the pointer in the member folders of the form parameter rhs. These pointers indicate each Folder pointing to the rhs. You need to add the pointer pointing to this Message to each Folder.
The function performs a loop through rhs. folders and calls the Folder member named addMsg to complete this task. The addMsg function adds the pointer to the Message to the Folder.
Void Message: put_Msg_in_Folders (const set
& Rhs) {for (set
: Const_iterator beg = rhs. begin (); beg! = Rhs. end (); ++ beg) {/** (* beg) removes the iterator reference. Release iterator reference to get a pointer to Folder * then the expression applies the arrow operator to the Folder pointer to execute the addMsg operation * pass this to addMsg, this Pointer Points to the Message */(* beg)-> addMsg (this) ;}} we want to add to the Folder );}}
4. Message assignment operator
Assigning values is more complex than copying constructors. Like a copy constructor, a value assignment must assign a value to contents and update folders to match the folders of the right operand. It must also add the Message to each Folder pointing to rhs. You can use the put_Msg_in_Folders function to complete the assignment. [However, note that the real parameters of the function are changed from folders to rhs. folders ].
Before copying from rhs, you must first delete it from each Folder that points to the Message. We need to iterate through folders to delete the pointer to this Message from each Folder of folders. The function named remove_Msg_from_Folders completes this task.
For remove_Msg_from_Folders and put_Msg_in_Folders that complete the actual work, the assignment operator is quite simple:
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;}
If the operands are different objects, call remove_Msg_from_Folders to delete the Message from each Folder of the folders member. Once this is done, the contents and folders members of the right operand must be assigned to this object. Finally, call put_Msg_in_Folders to add the pointer pointing to this Message to each Folder pointing to rhs.
After learning about remove_Msg_from_Folders, Let's see why the value assignment operator first checks whether objects are different.Delete the left operand when assigning a value.,And after revoking the member of the left operand,Assign the right operand member to the corresponding member of the left operand.. If the object is the same, the member that revokes the left operand also revokes the member of the right operand!
Even if an object is assigned to itself, the correct work of the assignment operator is also very important. A general method to ensure this behavior is to explicitly check the assignment of itself.
5. remove_Msg_from_Folders Member
void Message::remove_Msg_from_Folders(){ for (set
::iterator beg = folders.begin(); beg != folders.end(); ++beg) { (*beg) -> remMsg(this); }}
6. Message destructor
Message::~Message(){ remove_Msg_from_Folders();}
With the remove_Msg_from_Folders function, it is very easy to compile the destructor. We call the remove_Msg_from_Folders function to clear folders. The system automatically calls the string destructor to release contents and automatically calls the set destructor to clear the memory used to save folders members. Therefore, the only thing to do with the Message destructor is to call remove_Msg_from_Folders.
[Best Practices :]
The assignment operator usually needs to copy constructor and destructor. In this case, the common work should be put in the private utility function.
// P419 exercise 13.17 // under the private labor void addFldr (Folder * f) {folders. insert (f);} void remFldr (Folder * f) {folders. erase (f );}
// Question 13.19 void Message: save (Folder & f) {folders. insert (& f); f. addMsg (this);} void Message: remove (Folder & f) {folders. erase (& f); f. remMsg (this );}
// Expand: complete the Folder and Message classes, and complete the exercise 13.16 ~ 13.19 content // in Folder. h # ifndef FOLDER_H_INCLUDED # define FOLDER_H_INCLUDED # include
# Include
Class Message; class Folder {public: Folder (){}~ Folder (); void addMsg (Message *); void remMsg (Message *); private: std: set
Messages; void remove_Fldr_form_Messages () ;}; class Message {public: Message (const std: string & str = ""): contents (str ){}; message (const Message &); Message & operator = (const Message &);~ Message (); void save (Folder &); void remove (Folder &); void addFldr (Folder *); void remFldr (Folder *); private: std: string contents; std: set
Folders; void put_Msg_in_Folders (const std: set
&); Void remove_Msg_from_Folders () ;};# endif // FOLDER_H_INCLUDED
// In Folder. cpp # include "Folder. h" # include
Using namespace std; Folder ::~ Folder () {remove_Fldr_form_Messages ();} void Folder: addMsg (Message * rhs) {messages. insert (rhs);} void Folder: remMsg (Message * rhs) {messages. erase (rhs);} void Folder: remove_Fldr_form_Messages () {for (std: set
: Const_iterator beg = messages. begin (); beg! = Messages. end (); ++ beg) {(* beg)-> remFldr (this) ;}} Message: Message (const Message & m): contents (m. contents), folders (m. folders) {put_Msg_in_Folders (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;} Message ::~ Message () {remove_Msg_from_Folders ();} void Message: put_Msg_in_Folders (const set
& Rhs) {for (set
: Const_iterator beg = rhs. begin (); beg! = Rhs. end (); ++ beg) {(* beg)-> addMsg (this) ;}} void Message: remove_Msg_from_Folders () {for (set
: Iterator beg = folders. begin (); beg! = Folders. end (); ++ beg) {(* beg)-> remMsg (this) ;}} void Message: save (Folder & f) {folders. insert (& f); // update the directory to which the Message belongs. addMsg (this); // update directory} void Message: remove (Folder & f) {folders. erase (& f); // update the directory to which the Message belongs. remMsg (this); // update directory} void Message: addFldr (Folder * f) {folders. insert (f);} void Message: remFldr (Folder * f) {folders. erase (f );}