The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

'friend' in C++.

All C++ programmers know that using the 'friend' keyword an external class can be granted permission to peek into the class. Somehow, this appears to be a compromise wrt Encapsulation (Data Hiding).

Unable to accept that 'friend' cannot be strictly done away with, I believe that a really good decomposition of objects does not require to use 'friend'.

Has any of you expert C++ programmers faced such a situation where in you could not have done without a 'friend' ?

Friday, November 17, 2006
 
 
"a really good decomposition of objects does not require to use 'friend'" Why not? What if I've got a class which reveals some public accessors to some but allows special manipulation by a collection class so it declares the collection class as a friend. They are designed and implemented together.
onanon
Friday, November 17, 2006
 
 
A suggestion from http://www.amazon.com/Large-Scale-Software-Design-John-Lakos/dp/0201633620 is to avoid "long-distance friend", i.e. avoid specifying friend for a class which doesn't appear in the same header file as this one.

Here's an example which doesn't disobey that suggestion.

class FooCollection
{
public:
 class Foo
 {
  //let the FooCollection access private stuff, because some of the FooCollection methods are implemented via access to private Foo details which users of this header shouldn't access
  friend FooCollection;
 private:
  //reference to collection in which this item is contained
  FooCollection& mFooCollection;
  //other stuff
 public:
  //stuff available to users of this header
 };
private:
 //let the instances access private stuff, because some of the Foo properties are implemented via access to private FooCollection details which users of this header shouldn't access
 friend Foo;
 list<Foo> mList;
public:
 //stuff available to users of this header
};
Christopher Wells Send private email
Friday, November 17, 2006
 
 
> Unable to accept that 'friend' cannot be strictly done away with

They put in the language => they had a reason. :)

I see "friend" in C++ as analogous to "internal" in C#.
Christopher Wells Send private email
Friday, November 17, 2006
 
 
> I believe that a really good decomposition of objects
> does not require to use 'friend'.

If by really good you mean too open or too closed then you would be right. You can do away with friend if you make everything public or don't allow classes to cooperate. Both are less than optimal.

I allow anything in the same package to be friends where a package is very cohesive collection of related classes. This allows responsibilities to be clearly separated out into their own class while allowing access to the state they often need to operate on.
son of parnas
Friday, November 17, 2006
 
 
I've written x KLOC of C++ application code without using friend.  There's probably been a few cases where I made something public that could have been exposed only to friends but it hasn't been a problem.

I can see where it would be useful if you're writing API  code.
Mike S. Send private email
Friday, November 17, 2006
 
 
> I can see where it would be useful if you're writing API  code.

That's a good distinction. It's seldom necessary in application code. But if you're making libraries and frameworks and unit tests it can be very powerful.
son of parnas
Friday, November 17, 2006
 
 
I've always used 'friend's to implement mathematical operator overloads for custom classes (matrix, vector, etc)...

I'm sure there are other ways, but in my experience, it's the easiest way to make sure that LITERAL <OP> CUSTOM works just as well as CUSTOM <OP> LITERAL.
Andrey Butov Send private email
Friday, November 17, 2006
 
 
> Has any of you expert C++ programmers faced such a situation where in you could not have done without a 'friend'?

No, because the alternative always exists to loosen the access modifier on the field.  For instance, one use of friend in a recent project was so that a particular subclass could call a parent class's private constructor.  If "friend" didn't exist, one option would have been to make the parent constructor protected.  I don't want to go into details of why the constructor was private in the first place, but suffice it to say that I felt that adding a single friend declaration was more future-proof than changing the modifier on the constructor.

I hadn't seen the rule Christopher Wells cites, but that's another common use of friend IME.  The canonical RAII lock/locker pattern uses it:

class CriticalSection
{
    friend class CritSecLock;
    /* ... */
};

class CritSecLock
{ /* ... */ };

The third place I can recall using it is for serialization.
bmm6o Send private email
Friday, November 17, 2006
 
 
Ah yes, also what Andrey Butov says.  I haven't done it for mathematical operations, but often for operator <.
bmm6o Send private email
Friday, November 17, 2006
 
 
Friend is useful. It's not necessary, make everything public or make every private variable have accessor functions if you don't like friend. Both alternatives are inferior and a sign of poor design ability, but don't let that stop you.
Scott
Friday, November 17, 2006
 
 
"Friend" gets used for a lot of things, some good and some bad.  It definately has uses in COM programming, such as helping to tear down circular object references between cooperating classes when done with them.  Basically "release me" calls.

I generally force myself to re-examine my object model before committing to each "friend" exposure.  Some due diligence is a good thing, but there is no point in going through contortions to avoid friend methods.  The alternative usually means exposing something that shouldn't be public anyway.
Slim Simi
Friday, November 17, 2006
 
 
>> All C++ programmers know that using the 'friend' keyword an external class can be granted permission to peek into the class. Somehow, this appears to be a compromise wrt Encapsulation (Data Hiding).

This is a common myth.  A class uses 'friend' to grant access to its members to other specific classes.  A class can't grant itself 'friend' access to another class.  Because of this, 'friend' is typically going to only be used between two classes that are closely related and well known to each other.  It's not a general breaking of encapsulation.  If anything, 'friend' promotes encapsulation by limiting the scope of access to internal details to only those other classes that need it and that are well known to the class granting 'friend' status.  The alternative would be to expose those details through the public interface allowing all other classes to access it. 

The cases where I've had to use 'friend' (other than operator overloading) have typically been where I'm implementing an object model on top of some existing procedural interface that's been designed in a manner that forces either a less than ideal object model design or more than ideal level of intimacy between the objects. 

As far as I know, 'friend' came into existence in order to support operator overloads and that's probably its most common use.
SomeBody Send private email
Friday, November 17, 2006
 
 
I've always considered friend to be good for encapsulation, for the reasons you cite. The main situations that spring to mind are classes that know about one another's internals for efficiency purposes, and any instance when two classes (usually base classes) need to be tightly coupled in some way that is not interesting to the caller or the derived class.

I also use it a lot when cleaning up code; if you're upgrading an API, say, and you decide you need to make something private in a class, you can do that, and you can keep it all working temporarily by granting friendship to the classes that use it. Hardly perfect, but it prevents you getting distracted by something that you can usually put off for the moment, and you have a simple list (that the compiler will check for you!) of all the classes that need fixing by way of documentation.

Ultimately, friend allows you to have a smaller public interface, that exposes no unnecessary detail, whilst allowing the various pieces to work well together. Without it, all the mechanics of the coupling would be exposed in the public interface; with it, the coupling becomes a hidden implementation detail. To my mind, that's no bad thing.
Tom_
Friday, November 17, 2006
 
 
Here's an example:

I have a "Component" class and a "Container" class which can hold components (eg. in a GUI).

Each Component has a pointer to its parent Container.

The Container needs to set the pointer when a Component is added to it, but I *definitely* don't want a "setParent()" method in Component. The only way to do it is with friend:

eg.

class Component {
...
  Component *parent_;
  friend class Container;
};


class Container : public Component {
...
  void add(Component *c) {
    c->parent_ = this;  // I need access...!
    myChildren.push_back(c);
  }
};
Jimmy Jones
Saturday, November 18, 2006
 
 
Another example - overloaded operators can benefit from being free-standing, but having access to the internals of affected classes.

If you want an operator that takes an object of another type as an argument and want the order of the arguments to be transitive (e.g. like addition) then you need a free operator, not a member.

e.g.
ResultClass operator+( const OtherType &lhs , const Class &rhs ) { ... }
ResultClass operator+( const Class &lhs , const OtherType &rhs ) { ... }


As the operator is tightly coupled to the relevant classes, the coupling implied by 'friend' isn't a serious problem, and it allows the operator to access internal members, for efficiency.

Technically you could do without it, but it can make code a lot more readable.

Sunday, November 19, 2006
 
 
I've never found the need for friend when making freestanding operator overloads. The general template is to make a new value from the lhs with a copy construct, then return the result of a modifying operator (+=, -=, etc.). For complicated stuff, any potential inefficiency is dwarfed by the complication; for simple stuff, the compiler does as good a job as it can. (The important part appears to be not giving the compiler the impression that you want an actual non-temporary object; to this end, this approach is as good as constructing a new object with the result you want (this creating the usual need for friend), and certainly saves on code duplication.)

And no, I'm not sure how you end up with a non-const temporary (as required by the modifying operators) in this case -- but I copied this from an Andrei Alexandrescu post on comp.std.c++ aaaaages ago so it must be right.
Tom_
Sunday, November 19, 2006
 
 
There is a simple reason why friend is is logically desirable:

By itself a C++ class defines two things:

1. the memory layout of a particular kind (class) of C++ objects

2. which parts of the program (usually class members) have full access to the internals of objects of that kind. 

Usually you would want those two things to be defined such that there is 100% overlap, but that isn't necessarily logically true.
Sunil Tanna
Monday, November 20, 2006
 
 
I have not had any occasion in recent memory where "friend" was essential, but I have had many occasions where "friend" allowed a more transparent overall design for the reasons already given.

Whether it compromises encapsulation is probably a matter of interpretation. Since private access can only be granted and not demanded, a class still controls who sees inside it. But friend classes in C++ acknowledge that the best design may entail families of semi-intimate cooperating classes that are made more cohesive by allowing some access to internals. And then in the broader perspective that family of classes together enforces a more global encapsulation.

As with any such construct, you can misuse friends and throw encapsulation out the window. But that's certainly not what it was made for.
Jay Windley Send private email
Friday, December 08, 2006
 
 
Usually your code doesn't live in its own universe - it interfaces with other external entities.  You cannot modify these entities, yet you have to utilise a module referenced by function pointer.  If you're using an OO design (the fact that you've mentioined friend indicates that you are), then it may be necessary to have a pointer to inherited method as an interface item, and this is almost a no-no.  This is where friends also save the day, since they can be plain old C functions, which interact with your OO code.

For example, callbacks, threads etc are excellent friend candidates if the OS kernel expects a pointer to a 'C' function.
Haiku fan Send private email
Wednesday, December 13, 2006
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz