0
class Train{
public: 
    char direction;
    int loading_time, crossing_time;        
    ...

    friend std::ostream& operator<<(std::ostream& os, const Train& t){
        os << t.direction << '/' << t.loading_time << '/' << t.crossing_time;
        return os;
    }
};

Why is "friend" needed in this case? All attributes are public. Should I just use a struct instead?

  • 1
    `friend` is needed because the function is (inappropriately) defined inside the class. Without `friend` it would be a member function, with a different signature. – Pete Becker Feb 19 '22 at 22:50
  • 2
    When defined this way, as an inline friend function, it is a [hidden friend](https://stackoverflow.com/a/56796955/4641116) which is only accessible through ADL. (Some teams or companies actively avoid ADL, and even possibly take steps to neutralize ADL from being utilized by the C++ compiler. I'm okay with ADL, but something to be aware of.) – Eljay Feb 19 '22 at 22:58
  • _"Why is "friend" needed in this case?"_ `friend` is [**not** needed in this case](https://godbolt.org/z/Evj57P1Tf). `friend` grants access to a class's private members. This function does not need such access. – Drew Dormann Feb 19 '22 at 23:06
  • @DrewDormann without "friend" it doesn't compile – Chris Kouts Feb 19 '22 at 23:10
  • @ChrisKouts please see it compiling successfully in the link in my last comment. Making a function that doesn't need private access a `friend` serves no purpose and violates encapsulation. It's not needed and I don't recommend it. – Drew Dormann Feb 19 '22 at 23:14
  • "serves no purpose" is incorrect. Hidden friends do have advantages. – Jeff Garrett Feb 21 '22 at 04:21

1 Answers1

4

The friend is needed in order to make the function global. If you omit it, the function would be considered member function, in which case it should get only one parameter, and the caller should be of type Train (the class type in which we are declared), which doesn't fit our needs.

You can use in your case a global function instead:

class Train{
public: 
    char direction;
    int loading_time, crossing_time;        
    ...

};

std::ostream& operator<<(std::ostream& os, const Train& t){
    os << t.direction << '/' << t.loading_time << '/' << t.crossing_time;
    return os;
}

However, it is very common to use a friend function for this use case (instead of a non-friend global function), as it is declared inside the class, which is an important side bonus that you get.

Amir Kirsh
  • 12,564
  • 41
  • 74