Flowerpot
Flowerpot

Reputation: 23

Friend function cannot access private members

When reading C++ Primer I encountered the following snippet (I've omitted code that I think is irrelevant):

class Message {
  friend class Folder;

 public:
  // ...

 private:
  std::string contents;
  std::set<Folder*> folders;
  // ...
};

// ...
void swap(Message& lhs, Message& rhs) {
  using std::swap;
  for (auto f : lhs.folders) { f->remMsg(&lhs); }
  // class Folder is undefined by book
  // ...
}
// ...

C++ Primer gives a task to implement class Folder. So I add more code::

class Folder;   // my code

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

 public:
  // ...

 private:
  std::string contents;
  std::set<Folder*> folders;
  // ...
};

void swap(Message&, Message&);  // my code

// I added the whole class
class Folder {
  friend void swap(Folder&, Folder&);
  friend class Message;

 public:
  // ...

 private:
  // ...
  void addMsg(Message* m) { msgs.insert(m); }
  void remMsg(Message* m) { msgs.erase(m); }
};

void swap(Folder&, Folder&);    // my code

In file.cpp

void swap(Message& lhs, Message& rhs) {
  using std::swap;
  for (auto f : lhs.folders) { f->remMsg(&lhs); }
  // In vs2019 
  // Error (active) E0265   function "Folder::remMsg" is inaccessible
  // ...
}

As you can see, I can't use the method Folder::remMsg().

Then I try to figure out how friend function works.

struct B;  // This is [line 1]

struct A {
  friend void swap(A&, A&);

 private:
  int n;
  std::vector<B*> Bs;
};

void swap(A& lhs, A& rhs) {
  for (auto f : lhs.Bs) { f->n; }
  // f->n is still inaccessible
  // If I delete line 1, the code can be compiled successfully
  // same with class Folder
  // ...
}

struct B {
  friend struct A;

 private:
  int n;
  A C;
};

I don't understand why does this happen.

(I declare class Message and class Folder friend class with each other because I want symmetric swap to use copy-swap)

Upvotes: 2

Views: 874

Answers (1)

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 122458

void swap(Message& lhs, Message& rhs) is a friend of Message, but you try to access private members of Folder. Your last code has the same issue: friend void swap(A&, A&); is a friend of A but you try to access private members of B. friend is not transitive. Just because A is friend of B and swap is a friend of A does not mean swap is a friend of B.

If you want void swap(A&,A&) grant access to private member of B then make it a friend of B:

#include <vector>

struct B;

struct A {
  friend void swap(A&, A&);

 private:
  int n;
  std::vector<B*> Bs;
};

struct B {
  friend void swap(A&,A&);

 private:
  int n;
  A C;
};

void swap(A& lhs, A& rhs) {
  for (auto f : lhs.Bs) { f->n; }
                // ^^ access private member of A
                        //^^ access private member of B
}

Upvotes: 2

Related Questions