1

I'm overloading the insertion operator (<<) inside a struct using the following syntax:

struct Address{
    string street;
    string cross;
    int suite;

    friend ostream &operator <<(ostream &oss, const Address &other){
        oss<<"street: "<<other.street<<"cross: "<<other.cross<<"suite: "<<other.suite;
        return oss;
    }
};

I see that only if I declare the function as a friend of struct 'Address' does my code compile. As per my understanding a friend function is useful when there's a need to access the private members of a class. But, since in a struct all the members are public, there shouldn't be a need to declare the '<<' operator as a friend.

Could anybody please clarify the need of declaring '<<' operator here as a friend of the struct 'Address'?

  • 1) "_But, since in a struct all the members are public_" One can have `private` members in a `struct`. 2) Yes, there's no need to have the function as a `friend`, in **this** case. – Algirdas Preidžius Jan 15 '19 at 11:08
  • @AlgirdasPreidžius Answer in the answer section please, not here – Lightness Races in Orbit Jan 15 '19 at 11:09
  • 1
    CppCon 2018: Dan Saks “Making New Friends” https://www.youtube.com/watch?v=POa_V15je8Y – Robert Andrzejuk Jan 15 '19 at 11:09
  • @LightnessRacesinOrbit My comment, as-is, isn't a decent answer. Decent answer would need to better formatted, and not be as brief. I am, just to lazy, at the moment, to improve it, in those ways. – Algirdas Preidžius Jan 15 '19 at 11:11
  • @AlgirdasPreidžius You do not have to post an answer, so if you do not think you can write a full one, you can simply post nothing! But putting it here is not the way to work around that. Thanks – Lightness Races in Orbit Jan 15 '19 at 11:11
  • Without `friend`, it becomes a member function - like all other inline function definitions. – molbdnilo Jan 15 '19 at 13:39
  • It is particulary usefull in case of two classes accepting the same (one) parameter in nonexplicit constructor as explained by Nico Josuttis [here](https://www.youtube.com/watch?v=9-_TLTdLGtc) (around mark 28:00) – Croolman Jan 15 '19 at 14:38

1 Answers1

7

Indeed, that operator can be defined at namespace scope without friend.

You do not "need" to make it a friend in this case, for exactly the reasons you give, so it's not clear where you've heard that you do!

struct Address
{
   string street;
   string cross;
   int suite;
};

inline ostream& operator<<(ostream& oss, const Address& other)
{
   oss << "street: " << other.street << "cross: " << other.cross << "suite: " << other.suite;
   return oss;
}

(I made it inline on the assumption you're keeping the whole definition in the header, though in reality I'd probably declare it in the header then define it elsewhere.)

However a class defined with struct is still just a class and can still contain private members just fine. If you had one that did, you would once again need a friend.

Some people may choose to always make a friend function for consistency, and so that the definition of operator<< looks like it's "in" the class when you read it. Alternatively there may be some arcane lookup constraints that make this convenient (since a friend function defined in this way can only be found by ADL), though I can't think of any off the top of my head.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • Does that mean the only difference between a struct and a class in c++ is that by default all members in a class are private while in struct they are public? – Shubham Urkade Jan 15 '19 at 11:25
  • @ShubhamUrkade Actually, there is no such thing as "a struct" in C++; the keyword `struct` gives you a class. But close enough. – Lightness Races in Orbit Jan 15 '19 at 11:30
  • 1
    The inline friend function can be found only by Koenig lookup. One *may* have practical reasons to make it so. Prevent name collision in other places, maybe? I can't really think of an example off the top my head. Point is, I'm not sure it's right to say this is always about style. – StoryTeller - Unslander Monica Jan 15 '19 at 11:31
  • @StoryTeller Hmm could be an interesting point. I'm not going to investigate but I'll pay lip service to it and feel free to edit something in if you find something :) – Lightness Races in Orbit Jan 15 '19 at 11:31
  • @StoryTeller Had a feeling ;) – Lightness Races in Orbit Jan 15 '19 at 11:33
  • This operator declared in global scope should probably be declared `inline`, in order to match the code in the question. And also because the class is presumably defined in a header. (Or the operator could be defined outside of the header, if we don't mind deviating from the code in question). – eerorika Jan 15 '19 at 11:40
  • @StoryTeller: One case of useful `friend` is for template classes, allowing non template functions to use the template struct, `template struct S {friend void foo(S, T) {/*..*/}};` and `foo(S, 42)` (`42` used as `char`). – Jarod42 Jan 15 '19 at 13:43
  • @eerorika Could you please explain the reason for making it inline? – Shubham Urkade Jan 15 '19 at 14:33
  • 1
    @ShubhamUrkade Non-inline functions (that are used) must be defined in exactly one translation unit (as per *One Definition Rule*). Header files are typically included into multiple translation units, and therefore it is usually not OK to define non-inline functions in header files. When a function is defined inside a class definition (as you did), it is *implicitly* inline. When a function is defined in namespace scope (as in this answer), the function is implicitly non-inline. Thus the need for explicit inline declaration here. – eerorika Jan 15 '19 at 14:36
  • @StoryTeller: about the "strange" friend lookup and the reasons why one may desire it, https://stackoverflow.com/q/52122453/214671 may be interesting. The paper linked in the answer is particularly illuminating (and shows some really dark corners of C++). – Matteo Italia Jan 16 '19 at 08:57