第十三章 复制控制:(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);
}