c++primer 13章 Message-Folder类实现

1 c++primer 13 .4 Message-Folder类的实现

先上代码,图省事,就全写在.h里了。

还发现一个现象,函数定义如果直接写在class里,编译会报错,在下面写成inline就没问题了。

这可能涉及到一些编译时刻处理顺序的问题,我现在还在学习阶段,实在有点搞不懂这个。

//c++primer 13章练习

#pragma once
#include <string>
#include <set>

class Message;
class Folder {
public:
	friend Message;
	friend void swap(Message& first, Message& second);
	Folder() {}
    //Folder类的 拷贝、赋值运算符、swap 和Message类基本一样,就省略了
	~Folder();
	void addMessage(Message& m);
	void removeMessage(Message& m);
	bool hasMessage(const Message& m);
	const std::set<Message*>& getMessages() const;
private:
	std::set<Message*> messages;
};

class Message {
public:
	friend Folder;
	friend void swap(Message& first, Message& second);
	Message(const std::string& s = "");
	Message(const Message& that);
	Message operator=(Message that);
	~Message();
	void addToFolder(Folder& f);
	void removeFromFolder(Folder& f);
	bool isInFolder(const Folder& f);
	std::string& getContext();
private:
	std::string context;
	std::set<Folder*> inFolders;
};



inline Folder::~Folder() {
	for (auto& m : messages) {
		m->inFolders.erase(this);
	}
}

inline void Folder::addMessage(Message& m) {
	messages.insert(&m);
	m.inFolders.insert(this);
}

inline void Folder::removeMessage(Message& m) {
	messages.erase(&m);
	m.inFolders.erase(this);
}

inline bool Folder::hasMessage(const Message& m)
{
	return m.inFolders.find(this) != m.inFolders.end();
}

inline const std::set<Message*>& Folder::getMessages() const {
	return messages;
}

inline void swap(Message& first, Message& second) {
	using std::swap;
	for (auto& f : first.inFolders) {
		f->messages.erase(&first);
		f->messages.insert(&second);
	}
	for (auto& f : second.inFolders) {
		f->messages.erase(&second);
		f->messages.insert(&first);
	}
	swap(first.context, second.context);
	swap(first.inFolders, second.inFolders);
}

inline Message::Message(const std::string& s) {
	context = s;
}

inline Message::Message(const Message& that) {
	this->context = that.context;
	this->inFolders = that.inFolders;
	for (auto& f : that.inFolders) {
		addToFolder(*f);
	}
}

inline Message Message::operator=(Message that) {
	swap(*this, that);
	return *this;
}

inline Message::~Message() {
	for (auto& f : inFolders) {
		f->messages.erase(this);
	}	
}

inline void Message::addToFolder(Folder& f) {
	f.messages.insert(this);
	inFolders.insert(&f);
}

inline void Message::removeFromFolder(Folder& f) {
	f.messages.erase(this);
	inFolders.erase(&f);
}

inline bool Message::isInFolder(const Folder& f){
	return f.messages.find(this) != f.messages.end();
}

inline std::string& Message::getContext() {
	return context;
}



我在写代码过程中遇到的一些问题

我写的版本和书上的版本差别还是有点大的

  • 书上的版本往Folder添加Message用的save方法,调用到了f.addMsg(this),也就是说将Message存入Folder时,会同时更新Message和Folder里的set,但是使用Folder的addMsg却只会更新Folder自己的set,我个人感觉这非常不利于直观使用,但是如果将Folder::addMsg里也加上调用Message::save`的语句,那这两句就会一直循环调用

  • 所以在加入和移出信息时,我选择直接操作两边的set,不借用函数,这样就可以同时实现

    m1.addToFolder(f1);
    f2.addMessage(m2);
    

    更符合直观的使用

  • 不过这样我个人感觉也有不好的地方,两个类都直接操作了另一个类的private成员,感觉这和封装的理念有点冲突,虽然操作都只是一行代码inFolders.erase(this), 但还是不够优雅。(一些可能可行的建议)或许可以在Folder和Message里再分别加上一个private方法Folder::private_addMessage ; Message::private_addToFolder这两个方法不对外开放,只供内部和友元使用

    void Message::private_addToFolder(Folder& f) {
    	inFolders.insert(&f);
    }
    void Folder::private_addMessage( Message& m) {
    	messages.insert(&m);
    }
    

    这两个方法只对自己和友元开放,用来封装添加进set的语句

  • 不过总感觉这种写法还是不够优雅,不过继续下去改进可能就设计一些设计模式知识了,我个人还在学习过程中,目前能想到最好的写法就这个了,希望有大神看到了,能提点建议


版权声明:本文为lgg1111原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。