C++ 编译器不考虑友元类声明

Elg*_*rov 0 c++ friend private-members

我正在尝试重写教科书(C++ Primer)中显示的程序。这是一个类似电子邮件的小程序,包含两个 mainMessageFolder类。源文件如下:

\n

文件夹.h

\n
#pragma once\n\n#include <set>\n#include <string>\n\n#include "Message.h"\n\nusing std::string;\nusing std::set;\n\n\nclass Folder {\n    friend class Message;\n    friend void swap(Folder&, Folder&);\n\npublic:\n    Folder(const string &fname):\n        name(fname) { }\n    Folder(const Folder&);\n    Folder& operator=(const Folder&);\n    ~Folder();\n\n    void print_debug();\n\nprivate:\n    string name;\n    set<Message*> msgs;\n\n    void add_to_Message(const Folder&);\n    void remove_from_Message();\n\n    void addMsg(Message*);\n    void remMsg(Message*);\n};\n
Run Code Online (Sandbox Code Playgroud)\n

消息.h

\n
#pragma once\n\n#include <string>\n#include <set>\n\nusing std::set;\nusing std::string;\n\nclass Folder;\n\nclass Message {\n    friend class Folder;\n    friend void swap(Message&, Message&);\n\npublic:\n    // folders is implicitly initialized to the empty set\n    explicit Message(const string &str = ""):\n        contents(str) { }\n    // copy control to manage pointers to this Message\n    Message(const Message&);\n    Message& operator=(const Message&);\n    ~Message();\n    // add/remove this Message from the specified Folder's set of messages\n    void save(Folder&);\n    void remove(Folder&);\n\n    void print_debug();\nprivate:\n\n    string contents;\n    set<Folder*> folders;\n\n    void add_to_Folders(const Message&);\n    void remove_from_Folders();\n\n    void addFldr(Folder*);\n    void remFldr(Folder*);\n\n};\n
Run Code Online (Sandbox Code Playgroud)\n

文件夹.cc

\n
#include <iostream>\n\n#include "Message.h"\n#include "Folder.h"\n\nvoid swap(Folder &lhs, Folder &rhs) {\n    using std::swap;\n\n    lhs.remove_from_Message();\n    rhs.remove_from_Message();\n\n    swap(lhs.msgs, rhs.msgs);\n    swap(lhs.name, rhs.name);\n\n    lhs.add_to_Message(lhs);\n    rhs.add_to_Message(rhs);\n}\n\nFolder::Folder(const Folder &f):\n    msgs(f.msgs)\n{\n    add_to_Message(f);\n}\n\nFolder::~Folder() {\n    remove_from_Message();\n}\n\nFolder& Folder::operator=(const Folder &rhs) {\n    remove_from_Message();\n    msgs = rhs.msgs;\n    name = rhs.name;\n    add_to_Message(rhs);\n\n    return *this;\n}\n\nvoid Folder::addMsg(Message *msg) {\n    msgs.insert(msg);\n}\n\nvoid Folder::remMsg(Message *msg) {\n    msgs.erase(msg);\n}\n\nvoid Folder::add_to_Message(const Folder &f) {\n    for (auto m : msgs)\n        m->addFldr(this);\n}\n\nvoid Folder::remove_from_Message() {\n    for (auto m : msgs)\n        m->remFldr(this);\n}\n\nvoid Folder::print_debug() {\n    std::cout << "Folder name : " << name << std::endl;\n    std::cout << "Messages : ";\n    for (const auto msg : msgs)\n        std::cout << msg->contents << " ";\n    std::cout << std::endl;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

留言抄送

\n
#include <iostream>\n\n#include "Message.h"\n#include "Folder.h"\n\nMessage::Message(const Message &msg):\n    contents(msg.contents), folders(msg.folders)\n{\n    add_to_Folders(msg);\n}\n\nMessage& Message::operator=(const Message &rhs) {\n    remove_from_Folders();\n    contents = rhs.contents;\n    folders = rhs.folders;\n    add_to_Folders(rhs);\n\n    return *this;\n}\n\nMessage::~Message() {\n    remove_from_Folders();\n}\n\nvoid Message::save(Folder &f) {\n    folders.insert(&f);\n    f.addMsg(this);\n}\n\nvoid Message::remove(Folder &f) {\n    folders.erase(&f);\n    f.remMsg(this);\n}\n\nvoid Message::add_to_Folders(const Message &msg) {\n    for (auto f : msg.folders)\n        f->addMsg(this);\n}\n\nvoid Message::remove_from_Folders() {\n    for (auto f: folders)\n        f->remMsg(this);\n}\n\nvoid swap(Message &lhs, Message &rhs) {\n    using std::swap;\n\n    for (auto f: lhs.folders)\n        f->remMsg(&lhs);\n    for (auto f : rhs.folders)\n        f->remMsg(&rhs);\n\n    swap(lhs.folders, rhs.folders);\n    swap(lhs.contents, rhs.contents);\n\n    for (auto f : lhs.folders)\n        f->addMsg(&lhs);\n    for (auto f : rhs.folders)\n        f->addMsg(&rhs);\n}\n\nvoid Message::addFldr(Folder *f) {\n    folders.insert(f);\n}\n\nvoid Message::remFldr(Folder *f) {\n    folders.erase(f);\n}\n\nvoid Message::print_debug() {\n    std::cout << "Message content : " << contents << std::endl;\n    std::cout << "Exists in folders : ";\n    for (const auto f : folders)\n        std::cout << f->name << " ";\n    std::cout << std::endl;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

主程序.cc

\n
#include "Message.h"\n#include "Folder.h"\n\nint main() {\n    Folder f1("folder1");\n    Folder f2("folder2");\n    Message msg1("msg 1");\n    Message msg2("msg 2");\n    Message msg3("msg 3");\n\n    msg1.save(f1);\n    msg2.save(f1);\n    msg2.save(f2);\n    msg3.save(f2);\n\n    f1.print_debug();\n    f2.print_debug();\n    msg1.print_debug();\n    msg2.print_debug();\n    msg3.print_debug();\n\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

当我尝试使用命令编译这些源文件时:

\n
g++ main.cc Message.cc Folder.cc\n
Run Code Online (Sandbox Code Playgroud)\n

它给出错误:

\n
Message.cc: In function \xe2\x80\x98void swap(Message&, Message&)\xe2\x80\x99:\nMessage.cc:49:23: error: \xe2\x80\x98void Folder::remMsg(Message*)\xe2\x80\x99 is private within this context\n   49 |         f->remMsg(&lhs);\n      |                       ^\nIn file included from Message.cc:4:\nFolder.h:33:10: note: declared private here\n   33 |     void remMsg(Message*);\n      |          ^~~~~~\nMessage.cc:51:23: error: \xe2\x80\x98void Folder::remMsg(Message*)\xe2\x80\x99 is private within this context\n   51 |         f->remMsg(&rhs);\n      |                       ^\nIn file included from Message.cc:4:\nFolder.h:33:10: note: declared private here\n   33 |     void remMsg(Message*);\n      |          ^~~~~~\nMessage.cc:57:23: error: \xe2\x80\x98void Folder::addMsg(Message*)\xe2\x80\x99 is private within this context\n   57 |         f->addMsg(&lhs);\n      |                       ^\nIn file included from Message.cc:4:\nFolder.h:32:10: note: declared private here\n   32 |     void addMsg(Message*);\n      |          ^~~~~~\nMessage.cc:59:23: error: \xe2\x80\x98void Folder::addMsg(Message*)\xe2\x80\x99 is private within this context\n   59 |         f->addMsg(&rhs);\n      |                       ^\nIn file included from Message.cc:4:\nFolder.h:32:10: note: declared private here\n   32 |     void addMsg(Message*);\n      |          ^~~~~~\n
Run Code Online (Sandbox Code Playgroud)\n

为什么要抱怨私有方法,而FolderMessage却是朋友?

\n

nie*_*sen 6

由于该函数void swap(Message&, Message&)不是类的友元,因此在该函数内不允许Folder调用私有成员函数,例如Folder::remMsg()和。Folder::addMsg()