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

227 comments to 8.13 — Friend functions and classes

  • in the Quiz Point: 1c) where we split the files, is there a better way than having to make a forward declaration of one class (class Vector3d defined in its own .h) in another file, its confusing to me as usually in procedural we would just need a .h from a particular module which includes all the needed prototypes to use all of its component but now we can not do that because the friend functions require that its own class must be fully defined, i mean how in the OOP way where we would declare all needed items in a .h file and just to use the types within we just include this .h file ?

    • Hi Michael!

      You should only include what you need. Unnecessary includes slow down compilation and can cause circular includes, which prevent compilation altogether.
      @Point3d can be used without @Vector3d and so should be served without the include. If the user of the class wants to use the @moveByVector function they can include @Vector3d.h themselves.
      What you're describing (Having all includes in one file) is often done in libraries, because it's easier for the library to have everything at hand. These all-in-one files should be written at the very end of programming. Your code should work with as few includes as possible.

      • Okay i understand, also now if we include the vector3d.h we are able to use also the point3d.h because its included within it, so we could have compiled the program with the main file just including vector3d.h , is it better in this case to include all the class headers i will need ?

        • In this case, either way is reasonable. I'll use another example

          <iostream> includes <string>, so we can use @std::string in "main.cpp". As far as I know this isn't standard, but works with most compilers, let's assume it was standard.

          Should we include <string> alongside <iostream>?
          Yes, because the use our the <iostream> objects/functions is not related to our use of @std::string. We could remove one or the other without affecting our program, so we should include the individual headers. Even if we were sending @std::strings to @std::cout all over the place it's still better to include both headers, because we _could_ split their use apart.

          If @Vector3d was deeply integrated into @Point3d or the other way around and it's obvious that no one will ever use one class without the other, including a single header is fine.

  • Abdelrahman

    Thanks for this great tutorial.
    Could you please provide more explanation to this part:
    "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."

    • Abdelrahman

      I mean this specific part
      "  First, these public member functions have to be defined, which takes time, and can clutter up the interface of the storage class"

      • Alex

        An interface is another word for the public functions that the class exposes to be used by other classes. In the case of the example, Storage's only public function is the constructor to create it. And the members are stored privately, which means inherited classes can't access them. This means there isn't any way for a class outside of Storage to access the data that Storage is storing. To fix that, we could add access functions -- but now we've expanded the public interface of the class, and made those data elements directly accessible to whomever wants to access them. In this trivial example, that would be fine.

        But in a more complex example, say where Storage was storing things in a database, and you wanted Display to access the database without exposing the database to other classes, you wouldn't be able to accomplish this via accessors.

  • Silviu

    To be clear at friend classes: (the example)

    Storage is friend with - Display

    but

    Display it's not friend with Storage

    ??? am i correct ?
    I'm a little confused.
    quote: "Second, just because Display is a friend of Storage, that does not mean Storage is also a friend of Display."

    • Alex

      No, you have it backwards. Display is a friend of Storage, but not vice-versa.

      • Silviu

        What i don't get it, is that, you make friend class Display in class Storage to access the private members of Storage but you say that Display is a friend with Storage, but not Storage with Display, how Display gets access to Storage private members when it's not friend with Display (only Display is a friend of Storage, than Storage should have access too Display private members) ?
        I don't know what i'm missing, but i'm a little confused...

        • Alex

          Two things:
          1) Friendship is not bidirectional. If we make A a friend of B, that does not mean that B is a friend of A.
          2) Friendship allows the friend class to access your internals (e.g. your private area)

          So, when we do this:

          We're saying "Display is a friend of Storage", and as such, Display gets to access the internals of the Storage class (which it does in function Display::displayItem())

          Storage is not a friend of Display, and thus Storage has no access to the internals of the Display class.

          • Silviu

            Thank you for the explanation, i did understand the meaning of the word friend, but i think it's a little bit weird. For example if i'm a friend of you and you are not my friend, i could have access to your bank account and so on (it's like stealing), it doesn't fit very well in my logic, but probably this is the simplest way to access the class that you want. Thank you.

  • Trymacs

    Why we don't need here a forward declaration of Display?

    • Alex

      Because the language doesn't require a forward declaration when making one class a friend of another class that lives in the same namespace. You only need the forward declaration if you're friending classes in different namespaces.

  • Benjamin Collins

    Friend classes? More like friend classes with benefits, since they give each other access to their privates ; )

    • Trymacs

      I just meant in the following we have to do a forward declaration of Humidity because otherwise Temperature doesn't know about Humidity.

      But why we don't need here a forword declaration of the class Display?

      How does Storage know about Display?

      • Hi Trymacs!

        @printWeather has a parameter of type @Humidity, but at that point, it is unknown what @Humidity is, so you need to tell the compiler that @Humidity is a class.

        @Storage doesn't directly use @Display so you don't need a forward declaration. Line 15 makes it obvious that @Display is a class.

  • DecSco

    I'm using Code::Blocks as IDE and when trying to find out why my program doesn't compile, I found that the ticks for "Compile file" and "Link file" are not set for header files (and indeed, they mustn't be).
    Why is that so? I couldn't find an answer elsewhere online.

  • Peter Baum

    Regarding the Friend Class example in the lesson.  Since there is only one function, you could make that function a friend rather than the whole class.  I think a more realistic/useful example is needed.

  • Donlod

    i do not understand why we need a forward declaration of class Vector3d in Point3d.h while #include "Vector3d" is not working.
    So this is the not working solution:

    Point3d.h:

    Point3d.cpp:

    Vector3.h

    So this doesnt work and i get multiple errors(17) which do not make sense to me in this context 🙂
    It finally worked when moving #include "Vector3d.h" to point3d.cpp and adding forward declaration of class Vector3d to point3d.h.

    1. Why does it not work with #include?
    2. Does this mean when using a friend member function of a class that class is not allowed to #include the header of the class with the friend declaration?
    3. As i removed the #include "Vector3d.h" from Point3d.h the Vector3d parameter in the function declaration was marked as undefined (thats understandable so far) but after adding the #include "Vector3d.h" to Point3d.cpp the Vector3d parameter in Point3d.h was no longer marked as undefined even though i did not added the forward class declaration yet. How does Point3d.h know about Vector3d (this does not compile though)?

    • nascardriver

      Hi Donlod!

      1. You have circular includes.
      Vector3.h includes Point3d.h and
      Point3d.h includes Vector3.h.

      Includes work by copying the contents of the to-be-included header into the including file. Vector3.h ends up including itself, same for Point3d.h, this doesn't work.

      3. Your IDE's error highlighter is not a reliable source of information. All that counts is the compiler output.

      Use as few includes as possible in header files.

      • Donlod

        Thanks for the reply.
        > 1. You have circular includes.

        But doesnt the header guard prevent that a file is included multiple times? As an example when Point3d.cpp is being compiled it includes its header file which includes vector3d.h which again includes point3d.h. But since point3d.h was already included the header guard should prevent the file to be included this time.
        Looks like im missing something.

        • nascardriver

          I'd like to say you're right, but if you were, your code would work.
          I don't know why the header guards don't prevent circular includes, maybe someone else can help out.
          Anyway, avoid circular includes and favor forward declarations.

          • Donlod

            I think i spottet the problem, but im not sure about it:
            Looking at my example when including all the files into point3d.cpp it looks like this:

            If we are using the forward declaration and move the include to the .cpp file then it looks like:

            Even if the #defines are vice versa in the point3d.cpp file it works because then vector3d.h is included which includes point3d.h and the #include "point3d.h" in point3d.cpp is then blocked.

            I dont know if this is the correct reasoning but this seems reasonable to me.

            What I still not understand in this tutorial is:
            In the friend member function section alex says that the first example does not work because

            but then in the last code example of that section he says

            There is a mismatch with definition and declaration. Alex first says that storage has not seen the full definition of Display, but in the last he says it requires the full declaration of Display.
            This mismatch is also is the text below the code.

            • nascardriver

              > the #include "Point3d.h" is blocked here because it was already included through point3d.cpp
              No, vector3d.h doesn't know about and is not affected by Point3d.cpp.

              > There is a mismatch with definition and declaration.
              @Display has been moved above @Storage, so @Storage knows the full declaration of @Display. "Fortunately, this is easily resolved simply by moving the definition of class Display before the definition of class Storage."

              • Donlod

                > No, vector3d.h doesn't know about and is not affected by Point3d.cpp.
                What im thinking about is after moving the #define to point3d.cpp it looks like this.
                #include "Point3d.h"
                #include <iostream>
                #include "Vector3d.h"
                ...

                Doesnt Point3d.h get included first, then iostream and then vector3d.h? But since Point3d is already defined after the first #include its not again included by the #include in vector3d.h?

                The file looks then like this (the numbers represent the order the files are processed):

                > @Display has been moved above @Storage, so @Storage knows the full declaration of @Display. "Fortunately, this is easily resolved simply by moving the definition of class Display before the definition of class Storage."
                So the member function Display::displayItem is not part of the full definition of the Display class? Because in the third code example the definition of Display::displayItem is below the friend declaration.

  • Matt

    Took me a while to figure out why it wouldn't compile when I moved the class constructors out of the class' header file and into its .cpp.  Turns out, I had to take the default parameters out of the constructors in the class' .cpp files.  I think the solution to 8.13 quiz 1C should reflect this, since the example code in lesson 8.9 shows us how to move a constructor out of the class definition (but the example constructor there doesn't have default parameters to cause this confusion).

    Ref: Lesson 8.9 "Default parameters for member functions should be declared in the class definition (in the header file), where they can be seen by whomever #includes the header."

    Question: Is it necessary in Visual Studio 2017 to #include "stdafx.h" in every file?  I kept getting "fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add '#include "stdafx.h"' to your source?" until I put it in every single one.

    Side note: when adding files to my solution, I noticed that my options are C++ File (.cpp), Header File (.h), and a third, "C++ Class."  I gave Class a go and it seems pretty darn useful (automatically generates a header and a .cpp file with some very basic class syntax "stubs" in each one.  Do you ever use this functionality?

    Regards,
    Matt

    Point3d.h:

    Point3d.cpp

    Vector3d.h:

    Vector3d.cpp

    main.cpp:

    • nascardriver

      Hi Matt!

      > Is it necessary in Visual Studio 2017 to #include "stdafx.h" in every file?
      Disable precompiled headers in your project settings. Gone are your problems and welcome cross-platform code.

      > Do you ever use this functionality?
      I did when I used eclipse, it's useful. But vscode doesn't seem to offer an easy way for class templates so I'm back to creating files manually.

      General:
      Use this-> to access members

      Everything else is fine, good job!

      • Alex

        Just a quick note to say that I do not recommend explicitly using this-> to access members, unless you have a specific reason to do so (and have noted so in lesson 8.8). This is a stylistic issue, so you're certainly free to do as you wish. However, doing so is an uncommon practice, and is generally viewed as doing more harm (to readability) than good (to disambiguation).

  • Elchin Bunyatov

    Greetings Alex!

    I was trying to solve 1c for a while now and whatever I did (although I am pretty much sure I understood the lesson well enough) I've got the following error:

    ================================================
    Undefined symbols for architecture x86_64:
      "Point3d::moveByVector(Vector3d const&)", referenced from:
          _main in main-acc85f.o
      "Point3d::print()", referenced from:
          _main in main-acc85f.o
    ld: symbol(s) not found for architecture x86_64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    ================================================

    Then I gave up and opened the solution and found out that my code was exactly the same as yours. I copy-pasted your code, then tried to run and got the same error again.

    Stackoverflow did really help either...

    Do you have any ideas?

    I am using Atom Editor and Mac Terminal (High Sierra V. 10.13.2)

    • nascardriver

      Hi Elchin!

      Running clang++ 4.0.1-8 on Linux.

      I assume you ran

      which produces

      The problem is that clang doesn't compile all source files automatically, you need to tell clang to compile Vector3d.cpp and Point3d.cpp as well.

      Try this instead

  • Frederico

    Hello,

    for question 1c I had everything correct except the Point3d.h header file.
    Instead of forward declaring the Vector3d class like this:

    class Vector3d;

    I tried to include the Vector3d.h header file like this:

    #include "Vector3d.h"

    however that did not compile. I thought that by including the header file I would be able to use the class, just like I did in main(). I'm not sure why this didn't work.

    • Alex

      The issue is that two headers can not include each other (thus forming a circular reference). Vector3d.h already includes Point3d.h, so Point3d.h can't include Vector3d.h. That's why we have to use a forward declaration instead.

  • Hi,

    If we define one friend function like below, we are doing this by creating an object in Friend function, then what is the use of friend function, we can directly create an object to use Class members instead of create a Friend function?

    class A
    {
        int value;
        public:
        A(int x): value(x) {};
        int display()
        {
            cout << value << endl;
        }
        friend void fun(A &obj);
    };
    int main ()
    {
        A obj(10);
        obj.display();
        fun(obj);
    }
    void fun(A &obj)
    {
        std::cout << obj.value << std::endl;
    }

    • Alex

      In your case, there's no point, since you could have just had function fun() call a.display() (or just called obj.display()) directly.

      Making a function a friend is more useful when that function needs to access private members of the class directly, because there is no suitable public interface to that functionality.

  • Joseph

    Hi Alex,

    In your explanation of the friend member function, after the code was set properly:
    "Now everything will compile properly: the forward declaration of class Storage is enough to satisfy the declaration of Display::displayItem() inside the Display class, and the full definition of class Storage is enough to satisfy the definition of Display::displayItem()."

    Is it not the full definition of class Display satisfying the definition of Display::displayItem in being a friend of the Storage class?

    • Alex

      Yes, that too. I'll amend the statement.

      • Ishak

        I don't understand why the compiler needs to see definition of storage before seeing the definition of displayItem? isn't the forward declaration of storage enough to be able to define displayItem? can you please explain?

        thank you for the help

        • @displayItem accesses members of @Storage. In order to access those members, the compiler needs to know where they are located inside @Storage. A forward declaration isn't enough, because it doesn't tell the compiler anything about the class other than that is exists.
          The compiler can only know where members are located after they have been defined.

  • Rex Lucas

    Hi Alex
    I have heard mention elsewhere of "helper functions". I notice you don't mention them in any of your lessons. Are they relevant to C++? Are they perhaps somehow related to friend functions?
    Thanks

    • Alex

      A "helper function" isn't a well-defined term. It usually refers to some function that isn't meant to be called directly, but instead is called by other functions in order to help keep the code simpler (two simpler functions are better than one more complex function).

  • Serge Boucher

    Hi Alex,

    I've copied those 5 files into Code::Blocks 16.01 and got this error on line 9: undefined reference to 'Point3d::print()'
    I got error on lines 10 and 11 as well. Could it be a configuration problem of the GNU GCC Compiler?

    Thanks!

    • Alex

      Not sure -- main.cpp includes Point3d.h, which includes the definition of Point3d::print(), so I'm not sure why it would be complaining.

      • Matt

        As far as I can tell, Code::Blocks likes to assume you're only actually compiling "main.cpp" and nothing else.
        In other words, when you hit the "build" or "compile" buttons, it doesn't touch your other headers or sources for some reason.

        I fixed this by going to the "Project" section of the toolbar and:
        -Open up "Properties." This should open a menu titled "Project/targets options"
        -Open the "Build targets" tab
        -The bottom-most panel is called "Build target files:", where you can checkmark the files you wish to include in your build. Or you can just press the "All/? on" button directly beneath it.
        -compile and run as normal

        This worked for me, but YMMV

  • DOG_TRAINER

    Just out of curiosity. You defining the constructor and initializing the variables in the header file instead in the .cpp. Doesn't that violate the One-Definition Rule if the header file is included in other files???

    • Alex

      Great question. The answer is no for two reasons:
      1) Types are exempt from the one-definition rule, and class definitions are user-defined types.
      2) Member functions defined inside a class definition are considered inline, thus avoiding duplicate definition issues altogether.

  • Like in your last quiz, I tried to make 3 different files (Class.h, Class.cpp, and main.cpp)

    Also I defined the constructor of "Class" in the Class.cpp file.

    But when I try to access the constructor inside the main.cpp , it gives and error.

    "undefined reference to 'Class::Class()'

    I use CODE BLOCKS.

    please help.
    Thank you.

    • Alex

      Did you put the forward declaration for the constructor inside the class definition in the header file? e.g.

      in yourHeader.h:

  • John Halfyard

    For the multi-file (Q1c) version you have a lot more in your header file than I would have thought.

    You also start of the Point3d.h header file with the comment

    I thought header files are only used for declaration and the class *.cpp file is used for definition??

    • Alex

      This is a common point of confusion, and I haven't found a great way to explain it yet.

      Generally, your header files should include:
      * Function and variable forward declarations (not definitions)
      * Templates
      * User-defined type definitions

      To use a class, in most cases a code file needs to see the full definition of the class (it's not enough to see a forward declaration, because the forward declaration of a class doesn't tell the compiler anything about what members or access controls the class has).

      This means the class has to be defined in the header, so that the definition can be properly propagated. Normally defining something (such as a function) in a header file would put your program at risk of violating the one definition rule -- but types are exempt, precisely because they need to be propagated this way.

  • Luhan

    My quiz answers was like yours, but during the last question something happened before I found the solution, in the Point3d.h file if I do this:

    The compiler says I'm trying to redefine it, and I searched a little, and found it the problem was probably because it was inserting it more than once in the main function, but don't the Vector3d.h file does it as well(here the vector3d.h)?

    • Alex

      If Point3d.h #includes Vector3d.h, then if your main program #includes Point3d.h, you'll get Point3d.h and Vector3d.h. This shouldn't be a problem due to the header guards on both headers. If you ran into an issue, then most likely your header guards are incorrect, or you maybe tried to have the compiler compile a header file as if it were a code file.

  • Lim Che Ling

    Hi Alex,

    For this problem you mentioned: "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. "
    And the solution proposed has two 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." I thought only Step 1 will solve the problem?  There is no need to have step 2, right?

    • Alex

      No. The forward declaration for Storage allows Display to compile. The full definition of Display is needed to declare the friend function in Storage. The implementation of Display::displayItem requires having seen the full definition of the Storage class (otherwise it doesn't know any details about the Storage class, such as which members exist or are accessible)

  • Lim Che Ling

    Hi, Alex,

    In the last example, the definition of Display::displayItem() is moved out of Display class (after class Storage) because "needs to have seen the full declaration of class Storage". I can't figure out why does it need to see full declaration of class Storage? Is it due to parameter Storage &storage? If so, would not a forward declaration of class Storage would do? Or is it because the object storage needs to access private variables of Storage "storage.m_nValue" and "storage.m_dValue"?

    Also, I do not understand the Summary part "Note that making a class a friend only requires a forward declaration for the class". In the example in Friend Classes, the first class is Storage, followed by Display. In the class Storage, "friend class Display;" to make class Display a friend but you do not do forward declaration. Why the contradiction? I am confused. Thanks very much.

    • Alex

      I'm not sure I fully understand why friend member functions require the full definition and friend classes don't.

      In reference to the last bit, the friend class statement serves as the forward declaration. I've removed the statement about needing a forward declaration for a friend class in the summary, because the effective result is that you don't need to explicitly provide one.

  • Alexxx

    Quiz:
    Should be

    Also in 8-15-chapter-8-comprehensive-quiz.

    • Alex

      There's no such thing as a const void return value. I presume you mean function print() should be a const member function. Yes, it probably should (though it's not necessary for these examples since we don't create any const Point3d objects).

  • CrazyL

    Hello Alex,

    many thanks for your tutorial on "friend" declaration, finally one that lists not only the possibilities but also the quirks and dangers of the concept in a concise way! A question regarding quiz 1a (and the following) remains: Why not declare "v" as a const reference in "moveByVector()", i.e.

    As far as I learned here about const refs, there would be two benefits:
    1.) You can’t accidentally change v’s members in that function (possible, because all Point3d’s member functions are declared as friends of class Vector3d, at least in quiz 1a)

    2.) You could use R-values in expressions like this (did I use that term correctly here in combination with class objects?)

  • Lynsey Lehmann

    In the first example for "multiple friend functions" I am having difficultly understanding why it is necessary to define:
    [
    public:
        Temperature(int temp=0) { m_temp = temp; }

        void setTemperature(int temp) { m_temp = temp; }
    ]

    when "void setTemperature" is unused for the rest of the program and only "friend void printWeather(const Temperature &temperature, const Humidity &humidity);" is used for setting both temperature and humidity. I am confused on how they are all related and necessary to each other in the example.

    • Alex

      The Temperature constructor is used to set the temperature when the object is created. setTemperature is an access function to let you change the temperature _after_ the object has been created. But since it's not used in the example, I removed it. printWeather() doesn't set the temp and humidity, it just takes a Temperature and Humidity object and prints the values -- which it can do directly, since it's a friend of both classes.

  • OswyChow

    Hi Alex, i have a question that i hope isn't stupid:

    Why in the solution to exercise 1c in main.cpp and Point3d.cpp we #include both "Point3d.h" and "Vector3d.h" when it's enough to just #include "Vector3d.h" and have it #include "Point3d.h"?

    It's not that big of a deal but we save one line of code in both main.cpp and Point3d.cpp this way and it seems that the code compiles just fine.

    Or perhaps i'm missing something?

    Here's the code:

    main.cpp

    Point3d.h

    Point3d.cpp

    Vector3d.h

    Vector3d.cpp

    Sorry for my bad english and thanks for everything, learning how to program was my biggest dream and you're giving me the chance to make it happen!

    • Alex

      It's a best practice to always include all of the headers a code file includes directly. You shouldn't rely on headers to include other headers. That way, if the implementation of a header file changes in the future, your program won't break.

  • Mohsen

    Hi alex.
    i have a problem. all codes i've wrote were pretty the same as solution. and i get this errors:

    1>------ Build started: Project: 8.13, Configuration: Debug Win32 ------
    1>  Vector3d.cpp
    1>c:usersmohsendesktopprojectschapters8.138.13vector3d.cpp(9): fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add '#include "stdafx.h"' to your source?
    1>  Point3d.cpp
    1>c:usersmohsendesktopprojectschapters8.138.13point3d.cpp(16): fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add '#include "stdafx.h"' to your source?
    1>  Generating Code...
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

    i even changed my codes by yours and still i cant build the program. i googled it and tried to find precompiled header section on C++ menu of my project properties, but there isn't such thing in properties. i'm using VS2015 community

    • Alex

      You're using precompiled headers with visual studio, so the first line of each of your code (.cpp) files should be:

      #include "stdafx.h"

  • Brad

    Is there any problem with considering the friend keyword similar to the use of the static keyword and the only difference is the necessity to add the scope resolution operator if using the static keyword?

    For example, I modified the Value example to use a static bool isEqual member function prototype and it still compiled and produced the expected result:

    Would this only be a peculiarity with this example only? Or can static really be considered another way of achieving just what friend can achieve, just a little more verbosely?

    Fantastic lessons, btw. I'm really enjoying them.

    • Alex

      They are pretty similar.

      Ordinary member functions get 3 things:
      * Access to private members
      * Are considered in the scope of the class
      * Must be invoked on an instance of the class

      Friends only get the first. Static members get both the first and the second.

      You'd generally use a friend function when you want non-member functions of the class to have access to private members of the class. This is most often used for operator overloading.
      You'd generally use a static function when you want a member function of a class to be accessible without needing to have an instance of that class.

      • Brad

        Thanks heaps, that answers all the questions I had perfectly. Thanks again for these lessons too, they're an invaluable resource for someone like me.

  • Moj

    For exercise 1c I've copied and pasted just the same code as yours in VS2015, everything's fine except that it gives this single error:   Error C2653    'Point3d': is not a class or namespace name
    Would you please help?
    Thanks for great explanations.

  • Alexander Kindel

    In completing exercise c, I was surprised to find that it was mandatory to specify in the forward declaration of moveByVector that the parameter is a reference. Experimenting with

    seemed to suggest that whether of not the parameter is a reference counts for uniqueness for function overloading. Is that right? I guess I hadn't considered before how overloading interacts with forward declaration.

    What I actually did to begin with was not include a name for the parameter in the forward declaration, but I suppose it's impossible to do without one in this case because otherwise there's no syntax for specifying that it's a reference?

    • Alex

      Yes, you need to specify all the types, including whether they are pointers or references. You don't need to specify the parameter name for forward declarations. If your parameter is a reference, you can do this:

Leave a Comment

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