Problem
display
is not a friend
of A
, so display
cannot interact with id
, a private
member of A
.
A
is a friend
of B
. A
can interact with the internals of B
B
is a friend
of A
. B
can interact with the internals of A
int display(B&)
is not a member of B
, but it is a friend
of B
. It can interact with the internals of B
int display(B&)
is not a member of A
or a friend
of A
. It can NOT interact with the internals of A
. It does not inherit B
's friend
ship with A
through its friend
ship with B
. Only A
gets to decide who its friend
s are.
Solution
Decouple A
and B
by adding a display
function to A
and calling it from B
's display
function.
TL;DR Explanation
Easy fix is to make display
a friend
of A
. Easy, but now you're punching more holes in the encapsulation of your classes. This is a bad solution.
It is generally preferable to use free functions, but the more the friend
needs to know about the class's inner workings the more coupled they are and the less useful the recommendation becomes. display
not only needs to know B
has a vec
, it must also know that the A
s in vec
contain an id
. To me that's pushing it too far. If anyone changes A
or B
, display
likely needs to be changed. But what if you add
friend int display(A&);
to A
and call this display
overload from the B
display
overload? Now B
's display
only needs to know there is a display
function for A
s and knows absolutely nothing about what the other display
function does or what's in A
.
display
just knows it needs to call display
for all the A
s in vec
. It is a simple for
loop.
Here what the code could look like:
#include <string>
#include <vector>
#include <iostream>
class A {
// no need to be a friend of B
// const A& because a display function should not modify the displayed
friend void display(const A&);
private:
std::string id;
std::string name;
std::string label;
public:
A(); // if this constructor doesn't do anything, remove it.
// code that doesn't exist has no bugs.
// destructor removed. See Rule of Zero
};
class B {
// no longer any need to be a friend of A
private:
std::string num;
std::string data;
std::vector<A> vec;
public:
B(); // if this constructor doesn't do anything, remove it.
friend int display(const B&);
// destructor removed. See Rule of Zero
};
void display(const A& a){
// TESTING
std::cout << a.id << std::endl;
}
int display(const B& b){
// TESTING
for (const A & elem: b.vec) display(b.vec[0]);
return 1; // does 1 really make sense here?
}
Note the absence of friend
ship except for the display
functions.
The Rules of Three, Five, and Zero. Only Zero is relevant to this question, but familiarize yourself with the other rules. You cannot write complicated, efficient C++ code without knowing when and how to apply all three rules.
In general keep all of your functions as ignorant as possible and use helper functions to perform tasks they don't need to know the details of.
A
and return itsid
field? - Roy Avidandisplay
a class function ofB
, not a friend function - Damien