例如,我有这两个类(来自C ++ Primer的练习):
class Message{
set<Folder> folders;
public:
void addFolder(Folder f);
}
class Folder{
set<Message> messages;
public:
void addMessage(Message m);
}
方法addFolder(等于addMessage),如下所示:
void addFolder(Folder f){
folders.push_back(f);
f.addMessage(this);
}
void addMessage(Message m){
messages.push_back(m);
m.addFolder(this);
}
问题是这样我将对这两个方法进行无限递归调用(文件夹添加消息,而不是消息添加文件夹并要求文件夹添加消息等)。
我有两个解决方案:
1.在每个返回bool的类中有一个公共成员,该值表示给定的消息/文件夹是否在对象的集合中:
void addFolder(Folder f){
folders.push_back(f);
if(!f.search(this)){
f.addMessage(this);
}
}
void addMessage(Message m){
messages.push_back(m);
if(!m.search(this)){
m.addFolder(this);
}
}
这应该有效,但每次我必须控制套装两次。
另一个解决方案是在每个类中都有一个私有成员,只添加文件夹/消息而不要求另一个添加它。然后把它交给班上的朋友。
class Message{
friend class Folder;
set<Folder> folders;
public:
void addFolder(Folder f);
private:
void insertFolder(Folder f){ folders.push_back(f);}
}
class Folder{
friend class Message;
set<Message> messages;
public:
void addMessage(Message m);
private:
void insertMessage(Message m){ messages.push_back(m);}
}
addMessage和addFolder方法将是:
void addFolder(Folder f){
folders.push_back(f);
f.insertMessage(this);
}
void addMessage(Message m){
messages.push_back(m);
m.insertFolder(this);
}
这种方式不会有递归调用,而且性能更高。
在这样的情况下,使用朋友提高效率会很好吗?或者使用性能较低的方式(比如搜索方式?)并且不使用friend关键字会更好吗?
答案 0 :(得分:5)
您的设计存在很多问题。您正在递归,因为邮件中有文件夹和文件夹包含邮件。您需要比较文件夹和消息,并且您没有所有权的概念。
您需要暂时忘记代码并查看数据建模。
您有一组文件夹。我假设每个人都有一个文件夹ID。 你有一组消息。每个人都有一个消息ID。
您在文件夹和邮件之间存在多对多关系。
根据消息ID,您应该能够看到它包含的所有文件夹。 给定文件夹ID,您应该能够看到它包含的所有消息。
我假设&#34;文件夹有消息&#34;但实际上这只是一种多对多的关系。您可以使用两个多图来存储关系。
std::multimap< FolderId, MessageId >;
std::multimap< MessageId, FolderId >;
您还需要常规地图
std::map< FolderId, Folder >;
std::map< MessageId, Message >;
在最后两张地图中代替Folder
或Message
,您可以使用智能指针类型来启用放置和检索。我很简单并使用shared_ptr
。
您也可以在每个Folder / Message对象中包含一个集合,而不是多图。这只是从Id到Id的映射。然后,您可以参考&#34; manager&#34 ;,即主要地图以检索基础对象。
所以我们可以
class Message
{
std::set< FolderId > folderIds; // folders I am in
// implement construction and access functions etc.
};
typedef std::shared_ptr< Message > MessagePtr;
class Folder
{
std::set< MessageId > messageIds; // messages in this folder
};
typedef std::shared_ptr< Folder > FolderPtr;
将大地图放入某种经理
class MessageFolderManager
{
std::map< FolderId, FolderPtr > folders
std::map< MessageId, MessagePtr > messages;
};
请注意,对于依赖项,Folder和Message可能只需要知道其他类型的ID,而不是其他类型本身。因此,在Folder.h中,您只包含MessageId的标头定义,反之亦然。因此,您不会遇到依赖问题。经理需要包括所有类类型。