拷贝控制示例——Message和Folder

条件

  • 使用两个类设计,Message——表示电子邮件消息,Folder——表示消息目录。
  • 每个Message可以出现在多个Folder中。
  • 修改某一条Message,它在它所在的所有Folder中都会被修改。
  • Message使用一个set保存它所在的Folder的Folder指针。Folder也会用set保存它包含的Message的Message指针。
  • Message要有save和remove操作,向一个给定的Folder添加或删除一条Message。Folder也得有类似的操作。
  • 拷贝一个Message,将会拷贝其消息内容和保存Folder指针的set。同时每个包含此消息的Folder都添加一个指向新创建的Message的指针;销毁一个Message时,也要从包含此Message的所有Folder中删除指向此Message的指针。
  • 将一个Message赋予另一个Message时,左侧的Message会被右侧代替。同时更新Folder,将保存左侧Message的Folder中将它删除,然后添加右侧的Message

实现

框架

class Message
{
friend class Folders;
public:
	explicit Message(const string &str = "") : contents(str) {}
	Message(const Message&);
	Message& operator=(const Message&);
	~Message();
	void save(Folder&);
	void remove(Folder&);
private:
	string contents;
	set<Folder*> folders;
	//将本Message添加到指向参数的Folder中
	void add_to_Folders(const Message&);
	//从folders中的每个Folder中删除本Message
	void remove_from_Folders();
};

save和remove成员

void Message::save(Folder &f)
{
	//添加到folders,表示这个Folder保存了本信息
	folders.insert(&f);
	//将本信息添加到f的Message集合中
	f.addMsg(this);
}
void Message::remove(Folder &f)
{
	folders.erase(&f);
	f.remMsg(this);
}

拷贝控制成员

拷贝构造函数

拷贝一个Message,将会拷贝其消息内容和保存Folder指针的set。同时每个包含此消息的Folder都添加一个指向新创建的Message的指针

包含此消息的Folder们保存在folders中,所以如果拷贝一个Message,就要遍历该Message的folders,对其中每个Folder都要添加一个指向拷贝的新指针。拷贝构造函数和拷贝赋值运算符运算符都要完成这个工作,所以定一个一个函数完成这个公共工作(一般这种公共工作都是private的)

void add_to_Folders(const Message &m)
{
	for (auto f : m.folders)
		f->addMsg(this);
}

拷贝构造函数如下:

Message::Message(const Message &m) : 
	contents(m.contents), folders(m.folders) 
	{ add_to_Folders(m); }
析构函数

而当一个Message被销毁时,必须从所有指向此Message的Folder中删除它。拷贝赋值运算符也要做这个工作,所以还是定义一个private的函数:

void Message::remove_from_Folders()
{
	for (auto f : folders)
		f->remMsg(this);
}

tips:拷贝赋值运算符通常执行拷贝构造函数和析构函数中也要做的工作。这种情况下,公共的工作应该作为函数放在private中

同时就能定义析构函数:

Message::~Message() { remove_from_Folders(); }
拷贝赋值运算符

左侧的Message被右侧替代,就相当于左侧的Message被销毁(遍历左侧的folders,删除指向自己的Folder),然后拷贝为右侧的Message(遍历右侧的folders,添加指向拷贝的新指针)

Message& Message::operator=(const Message &rhs)
{
	remove_from_Folders();
	contents = rhs.contents;
	folders = rhs.folders;
	add_to_Folders(rhs);
	return *this;
}

自己的Message和Folder类

  • 实现了对应的Folder类
  • 添加了addFldr()函数和rmvFldr()函数,分别实现向当前Message对象插入/删除一个Folder
class Folder
{
	friend class Message;
public:
	explicit Folder(const string &str = "") : title(str) {}
	Folder(const Folder&);
	Folder& operator=(const Folder&);
	~Folder() { remove_from_Message(); }
private:
	string title;
	set<Message*> msgs;
	void add_to_Message(const Folder &f)
	{
		for (auto m : f.msgs)
			m->addFldr(this);
	}
	void remove_from_Message()
	{
		for (auto m : msgs)
			m->rmvFldr(this);
	}
	void remMsg(Message *m) { msgs.erase(m); }
	void addMsg(Message *m) { msgs.insert(m); }
};
Folder::Folder(const Folder &f) : title(f.title), msgs(f.msgs)
{
	//拷贝构造新的Folder
	//将老Folder消息集里的消息的set都添加上新Folder的指针
	add_to_Message(f);
}
Folder& Folder::operator=(const Folder &f)
{
	//拷贝赋值运算符函数,同时执行拷贝构造函数功能和析构函数功能
	remove_from_Message();
	title = f.title;
	msgs = f.msgs;
	add_to_Message(f);
	return *this;
}
class Message
{
public:
	explicit Message(const string &str = "") : contents(str) {}
	Message(const Message &m) : contents(m.contents), folders(m.folders) { add_to_Folders(m); }
	Message& operator=(const Message&);
	~Message() { remove_from_Folders(); }
	void saveTo(Folder &f)
	{
		folders.insert(&f);
		f.addMsg(this);
	}
	void addFldr(Folder *f) { folders.insert(f); }
	void removeFrom(Folder &f)
	{
		folders.erase(&f);
		f.remMsg(this);
	}
	void rmvFldr(Folder *f) { folders.erase(f); }
private:
	string contents;
	set<Folder*> folders;
	void add_to_Folders(const Message &m)
	{
		for (auto f : m.folders)
			f->addMsg(this);
	}
	void remove_from_Folders()
	{
		for (auto f : folders)
			f->remMsg(this);
	}

};
Message& Message::operator=(const Message &rhs)
{
	remove_from_Folders();
	contents = rhs.contents;
	folders = rhs.folders;
	add_to_Folders(rhs);
	return *this;
}

给Message类加上移动构造函数和移动赋值运算符

Message有string和contents和set的folders,如果用拷贝会比较耗时耗力,利用移动控制能避免产生额外开销。接管了旧Message的资源后就要更新folders,将旧Message换成接管了旧Message的新Message。用一个函数来实现这个操作:

void move_Folders(Message *m)
{
	folders = std::move(m->folders); //调用set的移动赋值运算符
	for (auto f : folders)
	{
		f->remMsg(m);
		f->addMsg(this);
	}
	m->folders.clear();
	//将老m置于可析构状态
	//确保销毁m没有别的影响
}
class Message
{
public:
	explicit Message(const string &str = "") : contents(str) {}
	Message(const Message &m) : contents(m.contents), folders(m.folders) { add_to_Folders(m); }
	//移动构造函数,因为是接管m,所以要从Floder中删除老的m,添加成新的接管了m的左侧对象
	Message(Message &&m) : contens(std::move(m.contents)) { move_Folders(&m); }
	Message& operator=(const Message &rhs)
	{
		remove_from_Folders();
		contents = rhs.contents;
		folders = rhs.folders;
		add_to_Folders(rhs);
		return *this;
	}
	//移动赋值运算符
	Message& operator=(Message &rhs)
	{
		if (this != &rhs)
		{
			remove_from_Folders();
			contents = std::move(rhs.contents);
			move_Folders(&rhs);
		}
		return *this;
	}
	~Message() { remove_from_Folders(); }
	void saveTo(Folder &f)
	{
		folders.insert(&f);
		f.addMsg(this);
	}
	void addFldr(Folder *f) { folders.insert(f); }
	void removeFrom(Folder &f)
	{
		folders.erase(&f);
		f.remMsg(this);
	}
	void rmvFldr(Folder *f) { folders.erase(f); }
private:
	string contents;
	set<Folder*> folders;
	void add_to_Folders(const Message &m)
	{
		for (auto f : m.folders)
			f->addMsg(this);
	}
	void remove_from_Folders()
	{
		for (auto f : folders)
			f->remMsg(this);
	}
	void Message::move_Folders(Message *m)
	{
		folders = std::move(m->folders); //调用set的移动赋值运算符
		for (auto f : folders)
		{
			f->remMsg(m);
			f->addMsg(this);
		}
		m->folders.clear();
		//将老m置于可析构状态
	}
};
Message& Message::operator=(const Message &rhs)
{
	remove_from_Folders();
	contents = rhs.contents;
	folders = rhs.folders;
	add_to_Folders(rhs);
	return *this;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值