第十三章 复制控制:(copy control)
复制构造函数(copy constructor)
复制操作符(assignment operator)
ps: 什么时候需要显示的定义复制控制操作:类具有指针成员,一般情况使用默认的复制控制
有的类 需要禁止复制构造函数, iostream类就不允许复制
类必须显示的声明其复制构造函数为private
最佳实践: 一般来说,最好显示或隐式定义默认构造函数和复制构造函数,只有不存在其他构造函数是才合成默认构造函数,如果定义了复制构造函数,也必须定义默认构造函数
//示例代码: //copy constructor : Sales_item(const Sales_item& orig): isbn(orig.isbn), units_sold(orig.units_sold), revenue(orig.revenue){} //assignment operator: Sales_item& operator=(const Sales_items& rhs) Sales_item& Sales_item::operator=(const Sales_item& rhs){ isbn = rhs.isbn; units_sold = rhs.units_sold; revenue = rhs.revenue; return *this; }
注解: | 实际上,应该将复制和赋值两个操作看作一个单元。 如果需要其中一个,我们几乎也肯定需要另一个。 |
13.3 析构函数(destructor)
何时调用析构函数:
/* * 撤销类对象时会自动调用析构函数 * 动态分配的对象只有在指向该对象的指针被删除时才撤销 */ void destructor_test(){ Sales_item* p = new Sales_item; {//new scope Sales_item item(*p);//copy constructor copies *p into item delete p;//destructor called on object pointed to by p }//exit local scope; destructor called on item }
提示: | 如果类需要析构函数,则它也需要赋值操作符和复制构造函数,这是一个有用的经验法则。这个规则常称为三法则(rule of three),指的是如果需要析构函数,则需要所有这三个幅值控制成员。 |
注解: | 撤销内置类型成员或复合类型的成员没什么影响。 尤其是,合成析构函数并不删除指针成员所指向的对象。(ps:所以 有指针对象成员的类 需要析构函数,需要复制构造函数 赋值操作符) |
消息实例 演示复制控制
#ifndef MESSAGE_H #define MESSAGE_H #pragma once #include <string> #include <iostream> #include <set> using namespace std; class Message; class Folder{ public: Folder(const string& s):folder_name(s){} Folder(const Folder&); Folder& operator=(const Folder&); ~Folder(); void save(Message&); void remove(Message&); void addMsg(Message*); void remMsg(Message*); private: set<Message*> messages; string folder_name; void put_Fldr_in_Message(const set<Message*>&); void remove_Fldr_from_Message(); }; class Message { public: Message(const 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: string contents; //actual message text set<Folder*> folders;//folders that have this message void put_Msg_in_Folder(const set<Folder*>&); void remove_Msg_from_Folders(); }; #endif // !MESSAGE_H
#include "stdafx.h" #include "Message.h" Message::Message(const Message& m):contents(m.contents),folders(m.folders) { put_Msg_in_Folder(folders); } void Message::put_Msg_in_Folder(const set<Folder*>& rhs){ for(set<Folder*>::const_iterator beg = rhs.begin(); beg != rhs.end();++beg) (*beg)->addMsg(this); } Message& Message::operator=(const Message& rhs){ if(&rhs != this){ remove_Msg_from_Folders(); contents = rhs.contents; folders = rhs.folders; put_Msg_in_Folder(rhs.folders); } return *this; } void Message::remove_Msg_from_Folders(){ for(set<Folder*>::const_iterator beg = folders.begin(); beg != folders.end();++beg) (*beg)->remMsg(this); } Message::~Message() { remove_Msg_from_Folders(); } void Message::addFldr(Folder* f){ folders.insert(f); } void Message::remFldr(Folder* f){ folders.erase(f); } void Message::save(Folder& fldr){ addFldr(&fldr); fldr.addMsg(this); } void Message::remove(Folder& fldr){ remFldr(&fldr); fldr.remMsg(this); } //Folder Folder::Folder(const Folder& f):messages(f.messages),folder_name(f.folder_name){ put_Fldr_in_Message(f.messages); } void Folder::put_Fldr_in_Message(const set<Message*>& rhs){ for(set<Message*>::const_iterator beg = rhs.begin(); beg != rhs.end(); ++beg) (*beg)->addFldr(this); } void Folder::remove_Fldr_from_Message(){ for (set<Message*>::const_iterator beg =messages.begin(); beg != messages.end(); ++beg) (*beg)->remFldr(this); } Folder& Folder::operator=(const Folder& rhs){ if(&rhs != this){ messages = rhs.messages; folder_name = rhs.folder_name; put_Fldr_in_Message(messages); } return *this; } Folder::~Folder(){ remove_Fldr_from_Message(); } void Folder::save(Message& msg){ addMsg(&msg); msg.addFldr(this); } void Folder::remove(Message& msg){ remMsg(&msg); msg.remFldr(this); } void Folder::addMsg(Message* msg){ messages.insert(msg); } void Folder::remMsg(Message* msg){ messages.erase(msg); }