When should you use friend classes? [duplicate]
Asked Answered
U

4

17

Possible Duplicate:
When should you use 'friend' in C++?

I have come to a stumbling block because of lack of documentation on friend classes. Most books just explain it briefly, e.g an excerpt from C++: the Complete Reference:

Friend Classes are seldom used. They are supported to allow certain special case situations to be handled.

And frankly, I have never seen a friend class in any good code made by an experienced C++ programmer. So , here is my list of problems.

  1. Do Inherited Classes have the same friends as there base classes? e.g, if I declare class foo as a friend of class base, will class der (derived from base) also have foo as a friend?

  2. What are the special case situations when a friend class should be used?

  3. I am making a winapi wrapper in which I want to make class WinHandle a friend of class Widget (to access some protected members). Is it recommended? Or should I just access them using the traditional Get/Set functions?

Ulaulah answered 16/7, 2011 at 15:5 Comment(3)
@thefromhere I am talking about friend classes specifically, not just the friend keyword.Ulaulah
@Everybody why the close votes?Ulaulah
Did you actually read the link provided? It clearly answers (2), which is the question posed in your title.Tentage
E
42

Friend is used for granting selective access, just like the protected access specifier. It's also hard to come up with proper use case where use of protected is really useful.

In general, friend classes are useful in designs where there is intentional strong coupling: you need to have a special relationship between two classes. More specifically, one class needs access to another classes's internals and you don't want to grant access to everyone by using the public access specifier.

The rule of thumb: If public is too weak and private is too strong, you need some form of selected access: either protected or friend (the package access specifier in Java serves the same kind of role).

Example design

For instance, I once wrote a simple stopwatch class where I wanted to have the native stopwatch resolution to be hidden, yet to let the user query the elapsed time with a single method and the units to be specified as some sort of variable (to be selected by user preferences, say). Rather than, have say elapsedTimeInSeconds(), elapsedTimeInMinutes(), etc. methods, I wanted to have something like elapsedTime(Unit::seconds). To achive both of these goals, I can't make the native resolution public nor private, so I came up with the following design.

Implementation overview

class StopWatch;

// Enumeration-style class.  Copy constructor and assignment operator lets
// client grab copies of the prototype instances returned by static methods.
class Unit
{
friend class StopWatch;
    double myFactor;
    Unit ( double factor ) : myFactor(factor) {}
    static const Unit native () { return Unit(1.0); }
public:
        // native resolution happens to be 1 millisecond for this implementation.
    static const Unit millisecond () { return native(); }

        // compute everything else mostly independently of the native resolution.
    static const Unit second () { return Unit(1000.0 / millisecond().myFactor); }
    static const Unit minute () { return Unit(60.0 / second().myFactor); }
};

class StopWatch
{
    NativeTimeType myStart;
    // compute delta using `NativeNow()` and cast to
    // double representing multiple of native units.
    double elapsed () const;
public:
    StopWatch () : myStart(NativeNow()) {}
    void reset () { myStart = NativeNow(); }
    double elapsed ( const Unit& unit ) const { return elapsed()*unit.myFactor; }
};

As you can see, this design achieves both goals:

  1. native resolution is never exposed
  2. desired time unit can be stored, etc.

Discussion

I really like this design because the original implementation stored the multiple of native time units and performed a division to compute the elapsed time. After someone complained the division was too slow, I changed the Unit class to cache the dividend, making the elapsed() method (a little) faster.

In general, you should strive for strong cohesion and weak coupling. This is why friend is so little used, it is recommended to reduce coupling between classes. However, there are situations where strong coupling gives better encapsulation. In those cases, you probably need a friend.

Enswathe answered 16/7, 2011 at 15:41 Comment(6)
Awesome answer! I am beginning to understand the importance of good design. (upvote).Ulaulah
Perfect answer. I like the stopwatch design. I have just spent 10 minutes trying to pick it apart but nothing is pick-able. I like the fact that you mention coupling. You could mention that tight coupling unto itslef is not a bad thing (when done correctly) and that friendship is a mechanism for documenting the coupling.Bendwise
@Martin: I like that last part of your comment "friendship is a mechanism for documenting coupling". I'll be using that!Hoi
@Martin: looking at this again, I noticed I missed the most important part of the implementation. There was no friend declaration in the example code! Just added it.Hoi
@André Caron: +1, Nice explanation and an Excellent example.Fletcher
Sorry, but where is the definition of NativeNow()?Anglocatholic
F
7

Do Inherited Classes have the same friends as there base classes? e.g if i declare class foo as a friend of class base, will class der (derived from base) also have foo as a friend?

The rule with friend keyword is:
Friendship attribute is not inherited.
So No friend of base class will not be friend of Derived class.


What are the special case situations when a friend class should be used?

Frankly, (IMHO) using friend classes is mostly done to achieve some things for rather ease of usage. If a software is designed taking in to consideration all the requirememtens then there would practically no need of friend classes. Important to note perfect designs hardly exist and if they do they are very difficult to acheive.

An example case which needs friend class:
Sometimes there may be a need for a tester class(which is not part of the release software) to have access to internals of classes to examine and log certain specific results/diagnostics. It makes sense to use friend class in such a scenario for ease of usage and preventing overhead of design.


I am making a winapi wrapper in which I want to make class WinHandle a friend of class Widget (to access some protected members). Is it recommended? Or should I just access them using the traditional Get/Set functions?

I would stick to the traditional setter/getter. I rather avoid using friend where I can get working through usual OOP construct. Perhaps, I am rather paranoid about using friend because if my classes change/expand in future I perceive the non inheritance attribute of friend causing me problems.


EDIT:
The comments from @Martin, and the excellent answer from @André Caron, provide a whole new perspective about usage of friendship, that I had not encountered before & hence not accounted for in the answer above. I am going to leave this answer as is, because it helped me learn a new perspective & hopefully it will help learn folks with a similar outlook.

Fletcher answered 16/7, 2011 at 15:6 Comment(9)
I didnt do it. I don't know why, but somebody is randomly downvoting every good answer. (An upvote to even things up)Ulaulah
Out of curiosity, How do you add those horizontal lines to your answer?Ulaulah
The use of friend classes for testing is strongly debated.Hoi
-1: For getter/Setter. That is the worst way to build you classes it ruins encapsulation. Also your opinion on why is misleading at best at worst wrong.Bendwise
@Martin: I do not contest the downvote, though why is the the opinion of why misleading? Atleast i may learn through your wise words.Fletcher
@Als: I completely disagree with this:using friend classes is mostly done to achieve some things for rather ease of usage.It is misleading to newcomers that we use friendship to break encapsulation just to make our life easier.We use friendship when their is a tight coupling between two entities that we want to reflect in the design. The use of the friend declaration in effect documents the tight coupling in addition to providing access. Friendship is done when two entities are designed together; the friend expanding the public interface of the class in a way that the class can't do alone.Bendwise
I would consider making the stream operator << and >> friends a good design option. As you are expanding the public interface of the class in a way the class can not do itself. These operators usually need to be friends so that they can efficiently stream the private data into/out of the object into the stream. Also making them friends publicly documents that that their is a tight coupling between these objects. (they are also usually the first functions you write for a class and are as such done at the same time).Bendwise
If you change the internal structure of a class. You must also update evreything that is coupled. The list of friends makes this easy all the tightly coupled objects.Bendwise
@Martin: Thanks, That opens me up to a new perspective about using friendship.Fletcher
R
1

friend usually accounts for where you would normally use one single class, but you have to use more because they have different life-times or instance counts, for example. friendship is not transferred or inherited or transitive.

Get/Set is quite terrible, although better than it could be. friend allows you to limit the damage to just one class. Usually you will make an intermediary class which is friended.

class MyHandleIntermediary;
class MyHandle {
    friend class MyHandleIntermediary;
private:
    HANDLE GetHandle() const;
};
class MyWidget;
class MyHandleIntermediary {
    friend class MyWidget;
    static HANDLE GetHandle(const MyWidget& ref) {
        return ref.GetHandle();
    }
};
class MyWidget {
    // Can only access GetHandle() and public
};

This allows you to change the accessibility of friendship on a per-member level and ensures that the extra accessibility is documented in a single place.

Ranch answered 16/7, 2011 at 15:10 Comment(7)
(+1). I understand. But why are Get/Set functions terrible?Ulaulah
@burningprodigy: Because they usually show that you haven't actually thought about your class design and are mindlessly exposing elements because you can. Get/Set only originated to be read back by automated reflection APIs, or used where binary compatibility was necessary (e.g. WinAPI), and never used in in-source code.Ranch
I see (Maybe that is why the WinAPI is so ugly). But what are the alternatives. like should i just declare the member I want to use Get/Set with as public?Ulaulah
@burningprodigy: Yes. The advantage of using friend this way is that only one class has access to them, improving the encapsulation. If you make them public to anyone, then you've increased the visibility.Ranch
@DeadMG: you forget about another valid get/set use case. Sometime s it is useful for the get or set to return a transformation of the actual member's value.Radarscope
@Evan Teran: You will notice that I still used a get in my code sample. I added usually for a reason, and that reason is that they definitely are more encapsulated than public member variables, just most of the time, YAGNI.Ranch
@Evan Teran: That is hardly ever required. get/set is a usually weak crutch for bad design. If an object needs to transform then it should know how to do it itself not an external entity.Bendwise
C
1

One of the cases where I applied the "friend classes", is where one class is composed or referenced by other (objects) classes, and the composing objects, require access to the internals of the main class.

enum MyDBTableButtonBarButtonKind {
  GoFirst,
  GoPrior,
  GoNext,
  GoLast
}

class MyDBTableButtonBarButtonWidget;

class MyDBTableButtonBarWidget {

  friend class MyDBTableButtonBarButtonWidget;

// friend access method:
protected:
  void GoFirst();
  void GoPrior();
  void GoNext();
  void GoLast();

  void DoAction(MyDBTableButtonBarButtonKind Kind);
};

class MyDBTableButtonBarButtonWidget {

private:

  MyDBTableButtonBarWidget* Toolbar;

public:

  MyDBTableButtonBarButtonWidget(MyDBTableButtonBarWidget* AButtonBar) {
    this ButtonBar = AButtonBar;
  }

  MyDBTableButtonBarButtonKind Kind; 
public:
  virtual void Click() { Buttonbar->DoAction(this Kind); }; 
};

void MyDBTableButtonBarWidget::DoAction(MyDBTableButtonBarButtonKind Kind)
{
  switch (Kind)
  {
     case MyDBTableButtonBarButtonKind::GoFirst:
       this.GoFirst();
     break;

     case MyDBTableButtonBarButtonKind::GoLast:
       this.GoLast();
     break;
  }
}

In this example, there is a widget control that is a bar composed of buttons, the buttonbar is referenced to a D.B. table, and has several buttons for a specific action, like select the first record of the table, edit, move to the next.

In order to do so, each button class has friend access to private & protected methods, of the given control. As previous answer in this post, usually friend classes act a single class, decomposed in several smaller classes.

It's not a finished example, its only a general idea.

Commixture answered 16/7, 2011 at 18:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.