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

184 comments to 8.13 — Friend functions and classes

  • Sean Kelly

    For question 1a to have the class Point3d a friend to Vector3d don’t we need to forward declare Point3d?

  • Omri

    Hello Alex,
    Consider modifying the text above as follows:
    1. Add definitions where indicated <…>.
    2. Replace declaration with definition where indicated *…*<…>.
    "To resolve this, we can switch the order of class Display and class Storage <definitions>. We will also need to move the definition of Display::displayItem() out of the Display class *declaration*<definition>, because it needs to have seen the definition of class Storage first."

  • Omri

    Hello Alex,
    "Note that making a class a friend only requires *as* forward declaration that the class exists"
    Is there a typo here (as should be a)?

  • Omri

    Hello Alex,
    Consider:
    "However, a better solution would have been to put each class ***declaration*** in a separate header file, with the function bodies in corresponding .cpp files. That way, all of the class ***declarations*** would have been visible immediately, and no rearranging of classes or functions would have been necessary."
    As we descussed earlier, is it not correct to replace ***declaration*** with ***definition*** in the above item?

  • Felipe

    Alex I have a question,

    Vector3d makes moveByVector a friend which is located in Point3d.h, and I tested out that when I #include "Vector3d.h" inside Point3d it does not let me access

    It says there is not enough permission to do so, my question is what happens if I want to include a .header file which is friending a function inside the .header file is being called from.

    • Alex

      You can’t do this -- if Point3d.h includes Vector3d.h, and Vector3d.h includes Point3d.h, then you’ve created a circular dependency that can’t be resolved.

  • Jacco

    Hi Alex, in the last exercise (creating the separate header and cpp files) I get a compiler error:
    ‘cout’ is not a member of ‘std’.
    I have included the <iostream> header in the cpp files. What could cause this problem (working in Visual Studio)

    • Alex

      1) Make sure that #include “stdafx.h” is the first line of the cpp file
      2) Make sure that #include <iostream> is included in all .cpp files that use std::cout, but below the stdafx include.

      If you’ve already done both of those things, I’m not sure what would cause this.

  • SotanahT

    Code provided in answer b is not compiling :

    I basically copy/pasted the solution in visual studio but not working

    • Alex

      What version of Visual Studio are you using? It compiles fine in 2015. This function should have direct access to v’s member functions because it is a friend of the Vector3d class.

      • SotanahT

        2015 as well.
        I agree that it should work considering the tutorial.
        Although, the example with the storage didn’t work either.
        Any idea of what could have gone wrong?
        Thanks again for all the hard work and your fast answer 🙂

  • Jas

    In friend function where we are making function parameter as object reference. Can’t we make pointer Like
    function(classname * pointer) rather than Function(classname &object)

    • Alex

      Yes, but generally if you can make something a reference, you should make something a reference, because references are safer than pointers.

  • john

    I think there’s a mistake in Vector3d.h:

    It should be

  • Rohit

    Why did we define humidity prototype first? Is it because printWeather() is accessing both the classes or do we have to always define the class prototype if we have two or more classes in an single program?

  • Pramesh

    Hey Alex, I basically copy pasted the solution for 1. c) and got the following error:

    I’m using codeblocks on a windows 10 machine, any idea?

  • Matt

    FYI the suggested solution for 1c fails on GCC 6.2.0 with -std=c++11 with the following compilation error:

    Vector3d.hpp:14:15: error: ‘Point3d’ has not been declared
       friend void Point3d::moveByVector(Vector3d &v);

    • Alex

      Is anybody else having this problem with GCC? I just recompiled the example on Visual Studio 2015 and it works okay, but sometimes Visual Studio is overly permissive.

      That said, just via inspection, I don’t see why that would be occurring since Vector3d.h includes Point3d.h, so the full definition of Point3d should be available. The only thing I can think is that maybe your Point3d.h is wrong (e.g. it still includes Vector3d.h), leading to a circular dependency.

  • Someone

    I guess friends always have access to each other’s privates

  • Hugh Mungus

    Hey Alex,

    I have hit a wall with the last question.

    Point3d.cpp

    Point3d.h

    Vector3d.h

    Vector3d.cpp

    main.cpp

    Whenever I compile, I get 6 errors:

    vector3d.cpp(6): error C2653: ‘Vector3d’: is not a class or namespace name

    vector3d.cpp(8): error C2039: ‘cout’: is not a member of ‘std’

    predefined c++ types (compiler internal)(208): note: see declaration of ‘std’

    vector3d.cpp(8): error C2065: ‘cout’: undeclared identifier

    vector3d.cpp(8): error C2065: ‘m_x’: undeclared identifier

    vector3d.cpp(8): error C2065: ‘m_y’: undeclared identifier

    vector3d.cpp(8): error C2065: ‘m_z’: undeclared identifier

    I’m not sure what I’m doing wrong. I am using Visual Studio 2015

  • hitman

    In the first example,reset() is itself a member function of class Accumulator,than why we make it friend of that class.??

    • Alex

      Friend functions are not members of the class, so reset is not a member of class Accumulator.

      In reality, we’d implement reset() as a member function, not a friend function, but this is just showing you the mechanics. We’ll see other situations in the future (particularly with overloaded operators) where we need to use friend functions.

  • Preston Becker

    For the last exam question, could you have included vector3d.h in point3d.h and point3d.cpp and skipped the forward declaration? If I’m writing a long program with multiple friendly member functions across many classes, do I have to manly include class declarations everywhere they are needed?

    • Alex

      > For the last exam question, could you have included vector3d.h in point3d.h and point3d.cpp and skipped the forward declaration?

      No, because vector3d.h needs to have seen the definition for Point3d so it can add Point3d::moveByVector as a friend -- if point3d.h included vector3d.h, then Vector3d would get included before the definition of Point3d, so the compiler would complain.

      The only place you need a forward declaration is in point3d.h so the function that references the Vector3d can resolve.

  • Thanks Alex, got it, your site is awesome..

  • Dohn jose

    Hi alex,
    Please find the code below, I tried to define a class object using new keyword. how can use this object in friend function.
    the below code showing compilation error

    • Alex

      “this” is a reserved word, so you can’t use it as a variable name. If you replace all instances of “this” with something else, your code will mostly compile. Then you just need to fix the name of main (it has to be main(), not main14()) and the statement with the missing semicolon.

  • chump

    Hi (again) Alex,

    I was wondering if it would be possible for two different classes to have member functions that are friends with the opposite class.
    ie:
    Class A’s member function, Print_B has access to B
    Class B’s member function, Print_A has access to A

    I ask this because when you write the A.h and B.h header files, you will need to #include the other’s .h file to get the full definition of the member function (ie: A.h will have to include B.h to access the definition of Print_A and vice versa). Thus, this creates a circular dependency, if I am not mistaken.

    • Alex

      I don’t think you can do this, as there is no way to remove the cyclic dependency. The best you could do would be to make one of the classes a friend of the other class, which doesn’t require a full class definition.

  • Nima

    Hello guys.
    Why this code come across with an error?

    I don’t realize why compiler gives an error because I already declare class C in first line(class prototype)
    Please help me.
    Cheers.

    • Alex

      Your declaration of C in the first line is a forward declaration. Forward declarations tell the compiler that an identifier exists, but not anything else about it (e.g. how large it is).

      When you create a class, the compiler needs to know how large objects of that class will be. This means you can’t declare member variables for classes who only have forward declarations.

      In other words, because the compiler doesn’t know how big C is (which is okay), it doesn’t know how big A is (which isn’t okay).

  • Horatio

    In the last question, why the constructors are contained in H file, and other functions in cpp?

  • Kattencrack Kledge

    On quiz "1c)"
    in main.cpp:

    We don’t need to #include "Point3d.h": Vector3d.h already includes Point3d.h in his file.

    Is including those two in main.cpp is good practice, or is it just redundant to do that?

    • Alex

      It’s good practice. At some point in the future, you may decide that Vector3d shouldn’t include Point3d any more -- and if you do that, then you’ll break all of the programs that were relying on Vector3d to include Point3d.

      It’s best practice to have every file directly include all of the headers it needs to function.

  • Hannah

    That makes sense. Thank you!

  • Hannah

    Hi,

    why do I have to use

    class Vector3d; // forward declaration for class Vector3d for function moveByVector()

    in point3d.h? Why can’t I omit the forward declaration and #include "vector3d.h" in point3d.h instead, since vector3d.h contains the Vector3d class definition?

    Thanks!

  • Serafeim

    Hi Alex,

    I think I found a minor typo in the quiz:
    In the quiz description and 1c) solution the z coordinate of the vector in main() is -2.0 (search for Vector3d v(2.0, 2.0, -2.0); ). However in 1a) and 1b) solutions it is -3.0 (search for Vector3d v(2.0, 2.0, -3.0); )

    Also, since this is my first comment, I would like to thank you for these wonderful tutorials.

  • Vlad

    Hello Alex

    Concerning the last quiz (and Shiva’s and SJ’s answers), I had the correct result, but then passed over it when codeblocks complained. To spare you the epic, it turned out that the header files needed to be marked for compiling, only, and *not* for linking. Archlinux x64, just in case someone else has the problems.

    • Rose

      I have the same problem with Windows 10 x64, and your solution does not work for me- maybe because it’s a different OS?
      If anyone has any idea why it’s not working, please let me know.

      My GNU GCC compiler’s errors, in main.cpp, are
      "undefined reference to ‘Point3d::print()’", and
      "undefined reference to ‘Point3d::moveByVector(Vector3d&)’".
      Also "error: 1d returned 1 exit status".

      I get these errors even after copy-pasting the solution from 1c, and currently both of the header files are marked for compiling only.

      I’d appreciate any potential solution to this.

      • Alex

        When you compile, do you see it compiling Point3d.cpp? It sounds like this is a linker error, where the linker is not able to connect the call to these functions to the function definition.

        • Rose

          I am still not sure what happened that caused it, but making a new Point3d.cpp from scratch helped.
          When I tried to compile Point3d.cpp on it’s own, the compiler error was "undefined reference to WinMain@16". I understand from some posts on stackoverflow.com that Point3d was somehow set to be a windows application instead of console application.

          By the way Alex, thank you very much for these tutorials! I have trouble going out much for a "regular" C++ course, and I can still study and learn thanks to your site 🙂

  • Dian Septiana

    Hi Alex,

    Why we need to include point3d.h in main.cpp again, while it’s already included in vector3d.h? I tried to include vector3d.h only in main.cpp, and the program executed without error. I confused, whether I need to re-include point3d or not in main.cpp, because include point3d in main.cpp seems redundant to me, while it’s already include in vector3d.h. CMIIW

    • Alex

      It may be redundant in this particular case, it’s best practice to always directly include all header files that you need in a given code file.

      At the very least, if later vector3d.h is rewritten to not include point3d, your code will still work.

  • Darren

    Better title choices for this chapter?

    "The Friend of my Friend is not my Friend"

    "Friends with benefits"

    "When it hasn’t been your day, your month, or even your year…"

  • Abhay Agarwal

    RESPECTED SIR;

    in EXAMPLE 1 of firend function why you have used ‘&’ sign before accumulator …without that also pragram is working…also u have passobject by value but not reference

    thanks in advance

    • Alex

      It’s a good idea to pass “objects” (non-fundamental data types) by reference instead of by value so you don’t make needless copies (which would still work, but be less performant).

  • Shiva

    > However, a better solution would have been to put each class declaration in a separate header file, with the function bodies in corresponding .cpp files.

    Heya Alex, I tried this on the quiz, and like SJ above, found it tricky (solved it with the help of your reply above). It’d be better if you put the proper way to do this in the lesson itself, or even better, as the third quiz question! In case you don’t bother writing it up, here’s my solution, feel free to use it:

    - point3d.h -

    - vector3d.h -

    - point3d.cpp -

    - vector3d.cpp -

    - main.cpp -

    Another thing I noticed, the non-static member initialisation in the quiz solutions is of no use, as you haven’t provided an empty default constructor (which you can’t either, as it would conflict with the current constructor). It’s kind of superfluous, isn’t it? I removed it in my solution.

    One last thing, there’s a typo in:
    > // error: Storage hasn’t see (seen) the full declaration of class Display

    I hope the comment wasn’t too long. 😀

    • Alex

      Good idea. I’ve added a quiz question, with your solution as the answer (with a couple of comment-related tweaks).

      Yes, the non-static member initialization was superfluous. I’ve removed it.

      Thanks for the typo fix!

      • Shiva

        Great! 🙂

        One small thing though: you’ve declared the class member variables in a single line in solutions 1a) and 1b); I believe you adhered to a declare-one-variable-at-a-time rule?

        No big deal, just for the sake of consistency. 😉

        P.S. Just noticed my solution is missing the ‘\’ in the ‘\n’s. (Point3d.cpp & Vector3d.cpp)

        • Alex

          True. With classes it’s a little more common to declare multiple related member variables together, if they’re all the same type, otherwise the class declarations can get a little long sometimes.

          I fixed the missing backslashes. Thanks for noticing!

        • Shiva

          Okay. Got it. Thanks! 🙂

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter