Reputation: 1750
I'm reading a code like this:
class Member
{
public:
friend std::istream& operator>>(std::istream& in, Member& m)
{
in >> m.name >> m.bYear >> m.bMonth;
return in;
}
friend std::ostream& operator<<(std::ostream& out,const Member& m)
{
out << m.name << " " << m.bYear << "." << m.bMonth;
return out;
}
private:
std::string name;
int year;
int month;
};
I never saw this way before. Is it a good practice to define nonmember function inside a class body with friend
? Any pros and cons?
Upvotes: 3
Views: 1882
Reputation: 106244
Is it a good practice to define nonmember function inside a class body with friend?
Indifferent practice, I'd say.
Any pros and cons?
the operators can refer to class members (nested classes, typedefs, enums, constants, static functions etc.) in the class's scope without needing to explicitly prefix them with the class name
it's convenient to have the streaming functions implicitly inline
- no One Definition Rule hassles
friendship means you can access all the non-public members conveniently
people studying the class source code are more likely to notice the streaming capabilities
as Mike Seymour commented, if the class is a template then defining a friend lets you omit the template <
...>
aspect of the operators, and refer to the instance argument simply as a const Member&
rather than a const Member<
...>&
.
you may want an out-of-line function definition so you can modify the implementation later and only need to relink (rather than recompile) client code
you're granting friendship that might not have been functionally necessary, that lessens encapsulation and therefore maintainability
people looking for a non-member streaming operator might not think to look in the class code
you could argue it "clutters up" the class definition source code, making it harder to take in the totality of the actual class members
As usual, the benefits of clean separation of interface and implementation - both for managing physical dependencies (the need to recompile rather than just relink) and for human readability - tends to increase for low level libraries used by disparate higher level libraries and applications, and be far lower for "private" support of local implementation (e.g. a class in an anonymous namespace in a .cpp
file, used only by that single translation unit, or - even more so - a private
nested class).
Upvotes: 5
Reputation: 154047
In general, it's not good practice; ideally, the implementation wouldn't even be in the same file as the class definition. (Ideally, too, we wouldn't have to declare the private parts in the header file either.) There are a lot of justified exceptions, however:
The most obvious is in really simple helper classes, where there really isn't enough to justify separating both parts. This is especially true if the helper class is defined locally, in the source file, rather than in a header.
Another case is for friends, particularly in templates. If
I write (even in a template) friend void f( MyClass& )
, then
I have declared a non-template to be friend, and I have to
implement a separate non-template function for each
instantiation type. If I provide the inline implementation in
the class definition, however, the compiler will automatically
create the separate non-template function for each type it is
used. This is a very frequent motivation for definition
operator>>
and operator<<
in the class, as they cannot be
members; often they will be declared as friend
even if they
don't need access to private members, just so that they can be
defined this way.
Finally, if there are no other declarations of the functions or operators, they are only visible within the class, or with ADL. Which shouldn't be a problem, as long as the function has at least one parameter which involves the class.
Upvotes: 4
Reputation: 556
Possible Pro: Easier to read and maintain, if you have all or most other functions handling the class' private members defined inside the class body as well. It keeps things together.
Con: Functions defined in the class body appear in every compilation unit instead of just one compiling the respective .cpp file you could put them in instead.
Upvotes: 1