C ++ - 使用好友关键字来提高效率?

时间:2014-08-08 09:39:01

标签: c++ performance friend

例如,我有这两个类(来自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关键字会更好吗?

1 个答案:

答案 0 :(得分:5)

您的设计存在很多问题。您正在递归,因为邮件中有文件夹和文件夹包含邮件。您需要比较文件夹和消息,并且您没有所有权的概念。

您需要暂时忘记代码并查看数据建模。

您有一组文件夹。我假设每个人都有一个文件夹ID。 你有一组消息。每个人都有一个消息ID。

您在文件夹和邮件之间存在多对多关系。

根据消息ID,您应该能够看到它包含的所有文件夹。 给定文件夹ID,您应该能够看到它包含的所有消息。

我假设&#34;文件夹有消息&#34;但实际上这只是一种多对多的关系。您可以使用两个多图来存储关系。

std::multimap< FolderId, MessageId >;
std::multimap< MessageId, FolderId >;

您还需要常规地图

std::map< FolderId, Folder >;
std::map< MessageId, Message >;

在最后两张地图中代替FolderMessage,您可以使用智能指针类型来启用放置和检索。我很简单并使用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的标头定义,反之亦然。因此,您不会遇到依赖问题。经理需要包括所有类类型。