C++ 编译器不考虑 friend class 声明

C++ compiler doesn't consider friend class declaration

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

Folder.h

#pragma once

#include <set>
#include <string>

#include "Message.h"

using std::string;
using std::set;


class Folder {
    friend class Message;
    friend void swap(Folder&, Folder&);

public:
    Folder(const string &fname):
        name(fname) { }
    Folder(const Folder&);
    Folder& operator=(const Folder&);
    ~Folder();

    void print_debug();

private:
    string name;
    set<Message*> msgs;

    void add_to_Message(const Folder&);
    void remove_from_Message();

    void addMsg(Message*);
    void remMsg(Message*);
};

Message.h

#pragma once

#include <string>
#include <set>

using std::set;
using std::string;

class Folder;

class Message {
    friend class Folder;
    friend void swap(Message&, Message&);

public:
    // folders is implicitly initialized to the empty set
    explicit Message(const string &str = ""):
        contents(str) { }
    // copy control to manage pointers to this Message
    Message(const Message&);
    Message& operator=(const Message&);
    ~Message();
    // add/remove this Message from the specified Folder's set of messages
    void save(Folder&);
    void remove(Folder&);

    void print_debug();
private:

    string contents;
    set<Folder*> folders;

    void add_to_Folders(const Message&);
    void remove_from_Folders();

    void addFldr(Folder*);
    void remFldr(Folder*);

};

Folder.cc

#include <iostream>

#include "Message.h"
#include "Folder.h"

void swap(Folder &lhs, Folder &rhs) {
    using std::swap;

    lhs.remove_from_Message();
    rhs.remove_from_Message();

    swap(lhs.msgs, rhs.msgs);
    swap(lhs.name, rhs.name);

    lhs.add_to_Message(lhs);
    rhs.add_to_Message(rhs);
}

Folder::Folder(const Folder &f):
    msgs(f.msgs)
{
    add_to_Message(f);
}

Folder::~Folder() {
    remove_from_Message();
}

Folder& Folder::operator=(const Folder &rhs) {
    remove_from_Message();
    msgs = rhs.msgs;
    name = rhs.name;
    add_to_Message(rhs);

    return *this;
}

void Folder::addMsg(Message *msg) {
    msgs.insert(msg);
}

void Folder::remMsg(Message *msg) {
    msgs.erase(msg);
}

void Folder::add_to_Message(const Folder &f) {
    for (auto m : msgs)
        m->addFldr(this);
}

void Folder::remove_from_Message() {
    for (auto m : msgs)
        m->remFldr(this);
}

void Folder::print_debug() {
    std::cout << "Folder name : " << name << std::endl;
    std::cout << "Messages : ";
    for (const auto msg : msgs)
        std::cout << msg->contents << " ";
    std::cout << std::endl;
}

Message.cc

#include <iostream>

#include "Message.h"
#include "Folder.h"

Message::Message(const Message &msg):
    contents(msg.contents), folders(msg.folders)
{
    add_to_Folders(msg);
}

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

    return *this;
}

Message::~Message() {
    remove_from_Folders();
}

void Message::save(Folder &f) {
    folders.insert(&f);
    f.addMsg(this);
}

void Message::remove(Folder &f) {
    folders.erase(&f);
    f.remMsg(this);
}

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

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

void swap(Message &lhs, Message &rhs) {
    using std::swap;

    for (auto f: lhs.folders)
        f->remMsg(&lhs);
    for (auto f : rhs.folders)
        f->remMsg(&rhs);

    swap(lhs.folders, rhs.folders);
    swap(lhs.contents, rhs.contents);

    for (auto f : lhs.folders)
        f->addMsg(&lhs);
    for (auto f : rhs.folders)
        f->addMsg(&rhs);
}

void Message::addFldr(Folder *f) {
    folders.insert(f);
}

void Message::remFldr(Folder *f) {
    folders.erase(f);
}

void Message::print_debug() {
    std::cout << "Message content : " << contents << std::endl;
    std::cout << "Exists in folders : ";
    for (const auto f : folders)
        std::cout << f->name << " ";
    std::cout << std::endl;
}

main.cc

#include "Message.h"
#include "Folder.h"

int main() {
    Folder f1("folder1");
    Folder f2("folder2");
    Message msg1("msg 1");
    Message msg2("msg 2");
    Message msg3("msg 3");

    msg1.save(f1);
    msg2.save(f1);
    msg2.save(f2);
    msg3.save(f2);

    f1.print_debug();
    f2.print_debug();
    msg1.print_debug();
    msg2.print_debug();
    msg3.print_debug();

    return 0;
}

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

g++ main.cc Message.cc Folder.cc

它给出错误:

Message.cc: In function ‘void swap(Message&, Message&)’:
Message.cc:49:23: error: ‘void Folder::remMsg(Message*)’ is private within this context
   49 |         f->remMsg(&lhs);
      |                       ^
In file included from Message.cc:4:
Folder.h:33:10: note: declared private here
   33 |     void remMsg(Message*);
      |          ^~~~~~
Message.cc:51:23: error: ‘void Folder::remMsg(Message*)’ is private within this context
   51 |         f->remMsg(&rhs);
      |                       ^
In file included from Message.cc:4:
Folder.h:33:10: note: declared private here
   33 |     void remMsg(Message*);
      |          ^~~~~~
Message.cc:57:23: error: ‘void Folder::addMsg(Message*)’ is private within this context
   57 |         f->addMsg(&lhs);
      |                       ^
In file included from Message.cc:4:
Folder.h:32:10: note: declared private here
   32 |     void addMsg(Message*);
      |          ^~~~~~
Message.cc:59:23: error: ‘void Folder::addMsg(Message*)’ is private within this context
   59 |         f->addMsg(&rhs);
      |                       ^
In file included from Message.cc:4:
Folder.h:32:10: note: declared private here
   32 |     void addMsg(Message*);
      |          ^~~~~~

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

因为函数 void swap(Message&, Message&) 不是 class Folder 的友元,所以对私有成员函数的调用如 Folder::remMsg()Folder::addMsg() 不是在该函数内允许。