Search

8.13 — Friend functions and classes

For much of this chapter, we’ve been preaching the virtues of keeping your data private. However, you may occasionally find situations where you will find you have classes and functions outside of those classes that need to work very closely together. For example, you might have a class that stores data, and a function (or another class) that displays the data on the screen. Although the storage class and display code have been separated for easier maintenance, the display code is really intimately tied to the details of the storage class. Consequently, there isn’t much to gain by hiding the storage classes details from the display code.

In situations like this, there are two options:
1) Have the display code use the publicly exposed functions of the storage class. However, this has several potential downsides. First, these public member functions have to be defined, which takes time, and can clutter up the interface of the storage class. Second, the storage class may have to expose functions for the display code that it doesn’t really want accessible to anybody else. There is no way to say “this function is meant to be used by the display class only”.

2) Alternatively, using friend classes and friend functions, you can give your display code access to the private details of the storage class. This lets the display code directly access all the private members and functions of the storage class, while keeping everyone else out! In this lesson, we’ll take a closer look at how this is done.

Friend functions

A friend function is a function that can access the private members of a class as though it were a member of that class. In all other regards, the friend function is just like a normal function. A friend function may be either a normal function, or a member function of another class. To declare a friend function, simply use the friend keyword in front of the prototype of the function you wish to be a friend of the class. It does not matter whether you declare the friend function in the private or public section of the class.

Here’s an example of using a friend function:

In this example, we’ve declared a function named reset() that takes an object of class Accumulator, and sets the value of m_value to 0. Because reset() is not a member of the Accumulator class, normally reset() would not be able to access the private members of Accumulator. However, because Accumulator has specifically declared this reset() function to be a friend of the class, the reset() function is given access to the private members of Accumulator.

Note that we have to pass an Accumulator object to reset(). This is because reset() is not a member function. It does not have a *this pointer, nor does it have an Accumulator object to work with, unless given one.

Here’s another example:

In this example, we declare the isEqual() function to be a friend of the Value class. isEqual() takes two Value objects as parameters. Because isEqual() is a friend of the Value class, it can access the private members of all Value objects. In this case, it uses that access to do a comparison on the two objects, and returns true if they are equal.

While both of the above examples are fairly contrived, the latter example is very similar to cases we’ll encounter in chapter 9 when we discuss operator overloading!

Multiple friends

A function can be a friend of more than one class at the same time. For example, consider the following example:

There are two things worth noting about this example. First, because PrintWeather is a friend of both classes, it can access the private data from objects of both classes. Second, note the following line at the top of the example:

This is a class prototype that tells the compiler that we are going to define a class called Humidity in the future. Without this line, the compiler would tell us it doesn’t know what a Humidity is when parsing the prototype for PrintWeather() inside the Temperature class. Class prototypes serve the same role as function prototypes -- they tell the compiler what something looks like so it can be used now and defined later. However, unlike functions, classes have no return types or parameters, so class prototypes are always simply class ClassName, where ClassName is the name of the class.

Friend classes

It is also possible to make an entire class a friend of another class. This gives all of the members of the friend class access to the private members of the other class. Here is an example:

Because the Display class is a friend of Storage, any of Display’s members that use a Storage class object can access the private members of Storage directly. This program produces the following result:

6.7 5

A few additional notes on friend classes. First, even though Display is a friend of Storage, Display has no direct access to the *this pointer of Storage objects. Second, just because Display is a friend of Storage, that does not mean Storage is also a friend of Display. If you want two classes to be friends of each other, both must declare the other as a friend. Finally, if class A is a friend of B, and B is a friend of C, that does not mean A is a friend of C.

Be careful when using friend functions and classes, because it allows the friend function or class to violate encapsulation. If the details of the class change, the details of the friend will also be forced to change. Consequently, limit your use of friend functions and classes to a minimum.

Friend member functions

Instead of making an entire class a friend, you can make a single member function a friend. This is done similarly to making a normal function a friend, except using the name of the member function with the className:: prefix included (e.g. Display::displayItem).

However, in actuality, this can be a little trickier than expected. Let’s convert the previous example to make Display::displayItem a friend member function. You might try something like this:

However, it turns out this won’t work. In order to make a member function a friend, the compiler has to have seen the full definition for the class of the friend member function (not just a forward declaration). Since class Storage hasn’t seen the full definition for class Display yet, the compiler will error at the point where we try to make the member function a friend.

Fortunately, this is easily resolved simply by moving the definition of class Display before the definition of class Storage.

However, we now have another problem. Because member function Display::displayItem() uses Storage as a reference parameter, and we just moved the definition of Storage below the definition of Display, the compiler will complain it doesn’t know what a Storage is. We can’t fix this one by rearranging the definition order, because then we’ll undo our previous fix.

Fortunately, this is also fixable in a couple of simple steps. First, we can add class Storage as a forward declaration. Second, we can move the definition of Display::displayItem() out of the class, after the full definition of Storage class.

Here’s what this looks like:

Now everything will compile properly: the forward declaration of class Storage is enough to satisfy the declaration of Display::displayItem() inside the Display class, the full definition of Display satisfies declaring Display::displayItem() as a friend of Storage, and the full definition of class Storage is enough to satisfy the definition of member function Display::displayItem(). If that’s a bit confusing, see the comments in the program above.

If this seems like a pain -- it is. Fortunately, this dance is only necessary because we’re trying to do everything in a single file. A better solution is to put each class definition in a separate header file, with the member function definitions in corresponding .cpp files. That way, all of the class definitions would have been visible immediately in the .cpp files, and no rearranging of classes or functions is necessary!

Summary

A friend function or class is a function or class that can access the private members of another class as though it were a member of that class. This allows the friend or class to work intimately with the other class, without making the other class expose its private members (e.g. via access functions).

Friending is uncommonly used when two or more classes need to work together in an intimate way, or much more commonly, when defining overloading operators (which we’ll cover in chapter 9).

Note that making a specific member function a friend requires the full definition for the class of the member function to have been seen first.

Quiz time

1) In geometry, a point is a position in space. We can define a point in 3d-space as the set of coordinates x, y, and z. For example, the Point(2.0, 1.0, 0.0) would be the point at coordinate space x=2.0, y=1.0, and z=0.0.

In physics, a vector is a quantity that has a magnitude (length) and a direction (but no position). We can define a vector in 3d-space as an x, y, and z value representing the direction of the vector along the x, y, and z axis (the length can be derived from these). For example, the Vector(2.0, 0.0, 0.0) would be a vector representing a direction along the positive x-axis (only), with length 2.0.

A Vector can be applied to a Point to move the Point to a new position. This is done by adding the vector’s direction to the point’s position to yield a new position. For example, Point(2.0, 1.0, 0.0) + Vector(2.0, 0.0, 0.0) would yield the point (4.0, 1.0, 0.0).

Points and Vectors are often used in computer graphics (the point to represent vertices of shape, and vectors represent movement of the shape).

Given the following program:

1a) Make Point3d a friend class of Vector3d, and implement function Point3d::moveByVector()

Show Solution

1b) Instead of making class Point3d a friend of class Vector3d, make member function Point3d::moveByVector a friend of class Vector3d.

Show Solution

1c) Reimplement the solution to quiz question 1b using 5 separate files: Point3d.h, Point3d.cpp, Vector3d.h, Vector3d.cpp, and main.cpp.

Thanks to reader Shiva for the suggestion and solution.

Show Solution


8.14 -- Anonymous objects
Index
8.12 -- Static member functions

346 comments to 8.13 — Friend functions and classes

  • srt1104

    In the class Storage and class Display problem, I tried fixing it by placing their definitions in separate header files but I'm getting errors in display.cpp.

    storage.h

    display.h

    display.cpp

    main.cpp

    • nascardriver

      storage.h includes display.h, but display.h includes storage.h, but storage.h includes display.h, but display.h includes storage.h, but storage.h includes display.h, ...

      display.h doesn't need storage.h. Use a forward declaration of `Storage` instead.

      • srt1104

        But it shouldn't lead to infinite circular calling since we use header guards.

        Here's what I believe happens when display.cpp begins compilation:
        First, it'll try to include display.h, since DISPLAY_H guard is not defined, it is defined and then it sees #include "storage.h".
        There, it notices STORAGE_H guard also hasn't been defined, so it gets defined and then it sees #include "display.h".
        But when there, as DISPLAY_H guard has already been defined, it'll ignore that whole file.
        Then it'll come back to storage.h and include rest of the code there into display.cpp.
        Then it'll come back to display.h and include rest of the code there into display.cpp.
        Then it returns to display.cpp and sees #include "storage.h" but since STORAGE_H guard has already been defined, it'll ignore the code there and return back to display.cpp and then the function definitions in display.cpp will get compiled.

        Similar thing will happen when the compiler tries to compile main.cpp.

        Without header guards it'll lead to infinite circular calling I can see that but how does that happen with header guards present?

        • nascardriver

          I was wrong, nice! That means I learned something new.

          The header guards in fact prevent an infinite recursive include. But when they're not fully included (Because the guard kicked in), you're missing dependencies.

          Manually resolving display.h (Pretend it's included in an otherwise empty source file)

          Step 1

          Step 2

          Step 3

          The definition of the `Storage` class depends on the declaration of `Display` but `Display` was never declared, because the header wasn't included (Because it can't be included).

  • Karl Phazer

    The quiz assignment 1c) was essential and revealing. After creating the files some copy/pasting I found myself pretty clueless. Although there has been mentions about laying classes in their own separate files and I'm very familiar with the concept in Java, I found the task harder than it should've been.

    Although laying everything in one file might be more concise and clear, I think it might be suboptimal approach. Like riding a bike, in order to learn programming one has to excercise it and I'd say the skill of structuring your code properly is to OOP what keeping balance is to bicycling. Thus, I hope the future lessons and/or chapters would have also multi-file implemented examples and most importantly quiz assignments with solutions.

    Don't get me wrong, I'm not saying you guys wouldn't be the best! :)

    Thanks!

  • MU

    Thanks again for a great lesson! You may want to add, though, that friend classes do not need to be forward declared (in the same namespace) if the entire class is "befriended". Otherwise, people may wonder why you did not forward declare class Display before making it a friend of class storage in the "Friend Classes" section. I thought it was an omission first, but then ran the code without errors and did some research to figure it out.

  • Yolo

    My question might sound a bit stupid, but i want to know so i can correct my programming gaps.
    In the last question, how can Point3d.h file know where to find class Vector3d?

    1) Is it done throught main.cpp?
    2) Is it done with the help of the forward declaration of Vector3d class, telling it that this class exists somewhere in the linking files?

    Thank you in advance.

    • nascardriver

      "Point3d.h" doesn't use anything that requires it to see the definition of `Vector3d`. We're only using a references and those work the same no matter what the type is. That means a forward declaration is enough to compile the header.
      `Point3d` is only using `Vector3d` in "Point3d.cpp", and "Point3d.cpp" includes "Vector3d.h", so the definition is visible.

  • Andreas Krug

    Small suggestion for code examples in chapters "Friend classes" and "Friend member functions":
    std::cout << storage.m_nValue << ' ' << storage.m_dValue << '\n'; instead of std::cout << storage.m_nValue << " " << storage.m_dValue << '\n';

  • Rushhahb

    >>#include "Point3d.h" // for declaring Point3d::moveByVector() as a friend

    can't we just use

    instead of including this #include "Point3d.h".

  • use of undefined type 'Display'

    >>This gives all of the members of the friend class access to the private members of the other class.

    I kept getting this error on line number 16: use of undefined type 'Display'. However, according to the sentence above, all  of the members of the friend class 'Storage' here access the private members of other class (Display)

    • use of undefined type 'Display'

      Here is the SOLUTION. Is it correct?

      • nascardriver

        Yes. The forward declaration allows you to declare references and pointers to `Display`, but you can't access `Display` until it is defined.

  • no direct access to the *this pointer

    >>First, even though Display is a friend of Storage, Display has no direct access to the *this pointer of Storage objects.

    How can this indirect access be possible?

  • Ambareesh

    For more context regarding making a friend member function:

    https://stackoverflow.com/questions/24095071/incomplete-type-in-nested-name-specifier

  • Jacob

    In Point3d.h why we need to forward declare Vector3d:

    and can't just #include Vector3d?

  • koe

    Is it possible for two classes to friend each other's member functions? It sounds like you can only have 1-directional member function friendship, since the definition order matters.

  • Cuong Nguyen

    hello. is that we can't read private members from friend function?I just can access and modify data from friend function? Is that true?

  • Nexteon

    Hey again, almost there to completion. For 1c), I noticed we keep reusing #include "Vector3d.h" and "Point3d.h". Is there a way to stop this? I thought that if you defined one of the .h files in another it would automatically be there for each file the other .h was in. For instance, if "Vector3d.h" was defined in "Point3d.h" then "Vector3d.h" would be defined in "Point3d.cpp" when "Point3d.h" is included.

    • nascardriver

      You'll want to separate code as much as possible. Otherwise you'll have to include things that you don't need, which increases the chance of name collisions and decreases compilation times.

  • Victor Keilhack

    I for some reason still remember the best practice tip way back in chapter 2.11 (https://www.learncpp.com/cpp-tutorial/header-files/): "Order your #includes as follows: your own user-defined headers first, then 3rd party library headers, then standard library headers, with the headers in each section sorted alphabetically."
    I got a little confused by the #include order in the quiz 1c). I did it in best practice fashion, which worked flawlessly, too.
    Thanks for this lesson, I feel like this one is really important but very complicated.

    Edit: wouldn't it be even more correct to make all void functions instead return the this-pointer?
    Eg. instead of
    [code]void Point3d::print() const
    {
        std::cout << "Point(" << m_x << " , " << m_y << " , " << m_z << ")\n";
    }[\code]
    do it like this:
    [code]//vv changed return type
    Point3d& Point3d::print() const
    {
        std::cout << "Point(" << m_x << " , " << m_y << " , " << m_z << ")\n";
        return *this; //added this
    }[\code]

  • hausevult

    >This allows the friend or class to work intimately with the other class, without making the other class expose its private members

    That sounded weird!

  • Wallayer

    Hi, I have a question about the solution in the point 1c) of the quiz specificaly in the file "Vector3d.h" in this line:

    What i assume i that the "Vector3d" that we're passig to the memeber function "moveByVector" is a class object?. and if it is, why we don't pass a "this" pointer.

    Thanks for the tutorial, keep it up :)

  • Parsa

    'Point3d' was not forward declared in the first solution. Also, why does the friend function declaration need to see the full class declaration?

    • nascardriver

      > 'Point3d' was not forward declared in the first solution.
      In the solution to 1a? There's no reason to forward declare `Point3d`.

  • Nguyen

    Is there any reason for that line to be there under the first example under Friend member functions?

    Thank you

  • Ilias Chatziefstathiou

    WARNING! at last solution of many file quiz: I had to add "const" in Vector3d.h at the end of print function declaration!
    God I have started writing like a C++ compiler. Thanks for the tutorials BTW, you rock!

  • ruchika malhotra

    Result -
    5 6.7true                                                                                                            
    2 3.7true

    No matter if I give false it's not deducting.

Leave a Comment

Put all code inside code tags: [code]your code here[/code]