Search

9.2a — Overloading operators using normal functions

In the previous lesson, we overloaded operator+ as a friend function:

Using a friend function to overload an operator is convenient because it gives you direct access to the internal members of the classes you’re operating on. In the initial Cents example above, our friend function version of operator+ accessed member variable m_cents directly.

However, if you don’t need that access, you can write your overloaded operators as normal functions. Note that the Cents class above contains an access function (getCents()) that allows us to get at m_cents without having to have direct access to private members. Because of this, we can write our overloaded operator+ as a non-friend:

Because the normal and friend functions work almost identically (they just have different levels of access to private members), we generally won’t differentiate them. The one difference is that the friend function declaration inside the class serves as a prototype as well. With the normal function version, you’ll have to provide your own function prototype.

Cents.h:

Cents.cpp:

main.cpp:

In general, a normal function should be preferred over a friend function if it’s possible to do so with the existing member functions available (the less functions touching your classes’s internals, the better). However, don’t add additional access functions just to overload an operator as a normal function instead of a friend function!

Rule

Prefer overloading operators as normal functions instead of friends if it’s possible to do so without adding additional functions.


9.3 -- Overloading the I/O operators
Index
9.2 -- Overloading the arithmetic operators using friend functions

49 comments to 9.2a — Overloading operators using normal functions

  • CC

    When we implement overloading of `operator+` as

    instead of

    don't we incur the overhead of the function call to `getCents()`? Or is it that those functions are simple enough that the compiler would almost certainly make the functions inline?

    • nascardriver

      those functions are simple enough that the compiler would almost certainly make the functions inline

      The benefit of using the access function `getCents()` is that if we ever decide to change the internals of `Cents`, eg. we store the value as euros, we don't have to update `operator+`, only the `getCents()` function.

  • Yousuf

    What is the difference between

    and

    ?

  • Raha

    I accidentally forgot to put 'const' keyword in front of 'getCents' member function and I got the following weird error:

    Severity    Code    Description    File    Project    Line    Suppression State
    Error    C2662    'int Cents::getCents(void)': cannot convert 'this' pointer from 'const Cents' to 'Cents &'    C:\Users\raha\Documents\Visual Studio 2019\Projects\learnCPP\learnCPP_cpp.cpp learnCPP    21

    What doesn't make sense to me is that operator function 'operator+' is not a member function but why the compiler gives us the warning about 'this' pointer?! There isn't any 'this' pointer used in the 'operator+'; instead, we have two Cents objects (c1, c2) which can not be refereed to by 'this'

  • Rushhahb

    >>that allows us to get AT m_cents without having to have direct access to private members.
    Is the use of 'at' above correct?

    >>

    I am kind of confused as the overload function  'operator+' is defined inside Cents.cpp and this file gets compiled. Why would we need to have prototype inside Cents.h too?

    • nascardriver

      I think that "at" can be there.

      Source files don't know about each other. "main.cpp" doesn't know that "Cents.cpp" exists not what's inside of it. "main.cpp" can only see "Cents.h".

  • Tom

    Hi!

    You should add the green frame in the rule at the end of the lesson.

    Thanks!

  • sv

    why is it important to return type cast value from the overloaded function when fundamental values will do?
    the above program will work normally like this too--

  • Rohit Alawadhi

    Whats wrong with this? Why we cant have 2 temp objects in one line?

    • nascardriver

      Non-const references can't bind to r-values. Your temporaries are r-values. `operator+` uses non-const references. If you don't intend to modify a reference/pointer parameter, make it `const`.

      • Rohit Alawadhi

        I have read this website quite diligently. And it answers all the questions I may have. Now even this reply makes me remember that non const is the problem. I feel sad that I forgot this. Did this happen to you when you started? How did you overcome this and how long did it take you to fix it?

        • nascardriver

          Sure, this happened to me. If you read some of the other people's comments (not just of this lesson), you'll see that forgetting `const` is a very common mistake. As you program, you'll make many more mistakes. You get frustrated over an error, but that's how you remember it. The next time you see that error, you know exactly what caused it last time and you can quickly fix it.

  • HoiNguyen

    Hi Alex and nascardriver
    I'm trying to overload operator in Derived class
    But i got an error: no suitable constructor exists to convert from "double" to "Derived"
    Can you help me pointing out what's wrong.
    Thanks you!
    My code below:

    • nascardriver

      `operator+` is declared to return a `Derived` (Line 36).
      You're returning a `double` (Line 38) (A `double` minus a `double` is a `double`.).
      A `double` is not a `Derived`, so a conversion must be made.
      There is no conversion (ie. `Derived(double)`) to a `double`.
      You get an error.
      Add a constructor to `Derived` that takes a single `double` parameter.

    • HoiNguyen

      Thanks nascardriver
      I tried and it works
      But i have another question.
      As you say:
      " `operator+` is declared to return a `Derived` (Line 36).
      You're returning a `double` (Line 38) (A `double` minus a `double` is a `double`.).
      A `double` is not a `Derived`, so a conversion must be made.
      There is no conversion (ie. `Derived(double)`) to a `double`.
      You get an error.
      Add a constructor to `Derived` that takes a single `double` parameter. "

      So why overloading operator at Base class doesn't get that error.
      And i try edit my code as:

      And it's working. Is it potential any risk? Do you have any advice.
      Thanks you!

      • nascardriver

        `Base` has a constructor that takes a single `double`. This constructor will be used for the conversion. `Derived` didn't have such a constructor (And the `Base` constructor can't be used to create a `Derived`).
        There's no issue with your new code. If it does what you want, it's correct. You should use brace initialization for higher type safety.

  • Hadi

    hello Alex
    What wrong with the code above ?
    I don't want to return anonymous object
    I want to return a normal object

    • Hello Hadi!

      - Initialize your variables with brace initializers.
      - Initialize members in the member initializer list.
      - You can only call on constructor during initialization. Line 21 tries to call `Cents::operator()`, but that doesn't exist. Initialize `a` with `x` in line 19, or return immediately.

  • Hello sir,

    Why we use

    ?

    I believe

    works just fine (At least when I tried).

    Ruturaj

  • CrazyL

    @Alex,

    guess here's a typo:
    - we’ll generally won’t differentiate them. --> we generally won't differentiate them

    The following sentence I had to reread a few times before I understood:
    - The one difference is that with the friend function, the friend function declaration inside the class also serves as a prototype.

    Perhaps an easier sentence structure is in order, like
    --> The one difference is that the friend function declaration inside the class serves as a prototype as well.

    Apart from that, the the lesson was great!

  • omri

    According to my questions and replies from 8.5, I think the following rephrasing is due:
    return Cents(c1.m_cents + c2.m_cents);
    is not an explicit call to the Cents(int x) constructor, but rather a syntax to create an anonymous Cents object with the required m_cents member. This anonymous object is returned to the caller etc.

    • Alex

      It's not a direct call to the Cents() constructor, but it does use the Cents() constructor, so saying we're "using" the constructor is appropriate.

  • Omri

    // note: this function is not a member function!
    Cents operator+(const Cents &c1, const Cents &c2)
    {// use the Cents constructor and operator+(int, int)
    // we can access m_cents directly because this is a friend function
    return Cents(c1.m_cents + c2.m_cents);
    }
    Is the following correct?
    // note: this function definition is not a member function definition!
    Cents operator+(const Cents &c1, const Cents &c2)
    {/*lt uses the Cents constructor explicitly and can access objects c1, c2 m_cents member directly because this is a Cents friend function*/
    return Cents(c1.m_cents + c2.m_cents);
    }

  • Omri

    In the first code section above:
    // add Cents + Cents using a friend function
    friend Cents operator+(const Cents &c1, const Cents &c2)
    would it be correct to say here:
    /*add Cents + Cents using a friend function named operator+
    note that this function is not a member function of the class.
    It is an "ordinary" function but special in the fact that it is given permission "by the class" to access this class's private members*/
    friend Cents operator+(const Cents &c1, const Cents &c2)

  • John

    Thank you for including an example using separate .h and .cpp files! Seeing the & in front of the parameters in the declaration

    helped solve a problem for me! I was only including the & in my function definition in my .cpp file.

  • Connor

    Hi Alex, why are we including the function prototype for

    in the header file?
    Since the .cpp file must be included in the solution is there anything wrong with defining the

    only in the .cpp file?

    • Alex

      We put the forward declaration of operator+ in the header so that any file that #includes Cents.h can use that operator+ without additional work (other than compiling Cents.cpp into the project).

      If you put the forward declaration in Cents.cpp, main.cpp won't see it there, since main.cpp can't see what's other code files while its being compiled.
      If you put the forward declaration in main.cpp, it would work for this program. But in a larger program, you'd have to do the same for every file that wanted to use this function, and that's a pain.

  • Devaraj

    Hi Alex,
    In the first code above , overloading function is not using the access function getcents(), than how it can access private members ? Hope the code is wrong!

    • Alex

      If a class makes a function a friend, that function can access the private members of the class as if it were a member of the class itself. In this case, our overloaded operator+ is a friend of class Cents, so it can access private member m_cents directly.

      That's the whole point of the lesson! :)

  • SUDARSHAN KOLAR

    Hi Alex... really nice lectures... thanks a ton...

    int getCents() const { return m_cents; }...

    why are we using the _const_ keyword above? Can you also please link where was this part discussed previously in chapters?

    Thanks
    Sudarshan

  • Darren

    "...touching your classes' internals,..." there's a joke in there somewhere.

  • Shiva

    This is the first time I'm seeing a chapter on this site without even a single comment, so I'll add one ;) :

    > Because of this, we can write our overloaded operator+ as a non-member: (in this context non-friend would be more appropriate)

Leave a Comment

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