Search

Language Selector

9.5 — Overloading unary operators +, -, and !

Overloading unary operators

Unlike the operators you’ve seen so far, the positive (+), negative (-) and logical not (!) operators all are unary operators, which means they only operate on one operand. Because they only operate on the object they are applied to, typically unary operator overloads are implemented as member functions. All three operands are implemented in an identical manner.

Let’s take a look at how we’d implement operator- on the Cents class we used in a previous example:

This should be straightforward. Our overloaded negative operator (-) is a unary operator implemented as a member function, so it takes no parameters (it operates on the *this object). It returns a Cents value that is the negation of the original Cents (by value). Because operator- does not modify the Cents object, we can (and should) make it a const function (so it can be called on const Cents objects).

Note that there’s no confusion between the negative operator- and the minus operator- since they have a different number of parameters.

Here’s another example. The ! operator is the logical negation operator -- if an expression evaluates to “true”, operator! will return false, and vice-versa. We commonly see this applied to boolean variables to test whether they are true or not:

For integers, 0 evaluates to false, and anything else to true, so operator! as applied to integers will return true for an integer value of 0 and false otherwise.

Extending the concept, we can say that operator! should evaluate to true if the state of the object is “false”, “zero”, or whatever the default initialization state is.

The following example shows an overload of both operator- and operator! for a user-defined Point class:

The overloaded operator! for this class returns the boolean value “true” if the Point is set to the default value at coordinate (0.0, 0.0, 0.0). Thus, the above code produces the result:

point is set at the origin.

Quiz time

1) Implement overloaded operator+ for the Point class.

Show Solution

9.6 -- Overloading the comparison operators
Index
9.4 -- Overloading operators using member functions

24 comments to 9.5 — Overloading unary operators +, -, and !

  • Shaun

    Is there an operator I can use to overload the usual if() effect? E.g.,

    What would happen in this case? Would C++ call the ! operator and reverse the result? Or is there another way to provide a boolean operator?

    • I think you could do this via overloading typecasts. If you provide an overloaded boolean conversion operator for your point, then I think the above example would work. This is covered in lesson 9.10.

      However, personally I wouldn’t recommend implementing it this way. The conversion from point to boolean isn’t very intuitive. I think this is better implemented as a member function that returns a boolean result -- in this way, your code will be more self-documenting. eg:

      • Adrian

        If I may add a remark: In my opinion Shaun is quite right … If you decide to have an operator!() to check whether a point is non-zero, then it might also be intuitive to have a means of checking the opposite condition.

        But considering the technical point of view, the usual way to do this would be a typecast to void *, even if this looks strange at first sight. This is because a pointer-to-void is perfectly legal as the expression of an if-statement, but it will not be automatically converted to many other things. As a consequence, typing errors are less likely to bite you, because they will produce compiler errors more often.

        A typical example are all std::ios objects, which provide a typecasting operator void *() (and the opposite operator!()) in order to check their state. Consider the stereotypical example, assuming n is an int:

        If std::cin had a conversion operator to bool, the second line would in fact compile, but it would certainly not do what you intended.

        • Gurjinder

          There is a problem with the typecast to void* approach. Because the object can be typecast to a void*, delete operator can be invoked on the object now (though the object is on stack):

          This can be disastrous!!!

  • Janez

    Is it ok to compare floating-point values like that (dX == 0.0)?

  • C++ newbie

    Hey there, I just want to say that this chapter has been an excellent read, and the tutorial so far has been a blast.  I came in with no prior experience and now I would consider myself sufficient in the language that I could write that I know it on my CV.  Thanks again for setting this website up.

  • Mr D

    Hi Alex,

    Something is confusing me!:

    With overloading the "-" operator, you use:

    But with overloading the "!" op’, you use:

    But why isn’t it:

    ??

    • Alex

      Generally when we overload operators, we try and keep them as close to the “intent” of the original operator as possible. So while you could make operator- multiply each of the dimensions in your Point by 2, that would be rather confusing, because we wouldn’t expect operator- to do that.

      Now let’s consider how operator! (logical NOT) works with normal variables. For a normal boolean value, it returns true when the boolean is false (0), and false when the boolean is true (1). For an integer, it returns true when the integer is 0, and false otherwise. We could generalize this to say that operator! returns true whenever our input value is a zero/null value, and false otherwise.

      What’s the zero value for a Point? Point(0.0, 0.0, 0.0) is the closest thing. So for consistency, it makes sense that our operator! return true when the Point is the zero Point (0.0, 0.0, 0.0) and false otherwise.

      If operator! did return a Point, what values would you expect it to have if you gave it Point(1.0, 2.0, 3.0) as input?

  • Mr D

    Thanks for the explanation, i get it!

  • phanhoang

    "Point operator- () const;"
    hey, i confused with that line, what "const" is meant??
    thanks you

    • Alex

      I means the function itself is const, and promises not to modify the internal state of the object it’s working on. This allows it to be called on const variables.

      • phanhoang17

        Oh, thanks: )))))

      • AKG

        Hey Alex, as i understand ‘operator-‘ modifies the member of class. If +ve value is converted to -ve value it will be stored in 2’s complement , right? So the stored value gets changed internally, though when we print it its value is same except sign change.

        • Alex

          Yes, if you convert a positive value to a negative value, the binary representation will change. However, the variable’s type does not change. For signed integers, the value will always be stored in two’s complement (positive numbers won’t have the sign bit set, negative numbers will).

          • AKG

            Yes Alex, I agree, but my question is what about the understanding of statement

            "Point operator- () const;"
            "It means the function itself is const, and promises not to modify the internal state of the object it’s working on. This allows it to be called on const variables"

            So here Operator- () modifies internal state of object, right ? But const key says it will not modify the internal state of object.

            • Shiva

              No it doesn’t. If you look closely at the implementation of operator-, you’ll see that all it does is create an anonymous object of Point class and return it to the caller. It doesn’t modify the parent object’s members; it accesses them only to call the Point() constructor with [the negatives of] those values.

              Hope that helps. :)

  • OPENG

    #include <iostream>

    class Point
    {
    public:
        double m_x, m_y, m_z;

    public:
        Point(double x=0.0, double y=0.0, double z=0.0):
            m_x(x), m_y(y), m_z(z)
        {

        }

            Point operator- () const;

            Point operator+ () const;

            // friend std::ostream& operator<< (std::ostream& out, const Point& point);
            friend std::ostream& operator<< (std::ostream& out, Point& point);

            double getX() const { return m_x; }
            double getY() const { return m_y; }
            double getZ() const { return m_z; }
        };

    Point Point::operator- () const
    {
        return Point(-m_x, -m_y, -m_z);
    }

    Point Point::operator+ () const
    {
        return Point(m_x, m_y, m_z);
    }

    // friend std::ostream& operator<< (std::ostream& out, const Point& point);
    std::ostream& operator<< (std::ostream& out, Point& point)
    {
        out << point.getX() << " " << point.getY() << " " << point.getZ();
        return out;
    }

    int main()
    {
        Point point(2.3, -4.6, 2.5);

        std::cout << point << ‘\n’; // It works

        std::cout << +point << ‘\n’; // It doesn’t work at all. I am confused about that.
        std::cout << -point << ‘\n’;

        Point point2 = +point;
        std::cout << point2 << ‘n’; // It also works

        return 0;
    }

    Hey, Alex. I have a few questions.
    ① Does +point or -point a const Point object?
    ② But when i change the 2th parameter of the << overloading operator function into "const Point& point",
       it works,Why??
    I thinks it’s a rvalue, right?
    Thanks a lot:)

    • Alex

      1) No, it can work on a const or non-const object (you can always make a non-const object const, but not the other way around).
      2) The problem is you’re trying to pass an anonymous object (the Point returned by operator+) by non-const reference to operator<<. You can’t do that. As you’ve already noted, making the parameter const addresses the issue (and it really should be const anyway, since operator<< doesn’t modify the parameter).

  • OPENG

    Hey Alex,
    I have found where the problem is, Because it’s a anonymous-objects, so it’s a rvalue, you must be refer to by value or const reference.. Yeah, Thanks !!

  • Jens

    Hey Alex. I have two questions:
    1) In the first example, where you overloaded operator-, you used you overloaded operator like this:

    Doesn´t that example just use the normal operator-? I mean, getCents returns a double and it just seems as though the operator- just uses that double to perform the built in operator- function. I took away the whole overloaded operator and it still works.

    2)In the quiz your answer is:

    Are the -m_y and -m_z just typos or am I missing something?

    Sorry if these questions are stupid, but it always bugs me when I´m left wondering about something, so I thought I´d make a question.

    • Alex

      1) Hah, you found an error. It was using getCents to return a double and then applying operator- to the double. I’ve updated the example so it executes like I intended:

      Now operator- will be applied to the Cents object first, and then getCents() will be called on the result.

      In this particular example, it ends up the same result either way.

      2) The -m_y and -m_z were copy/paste errors from the overloaded operator-. I’ve fixed them. Thanks for pointing that out.

  • Eelco

    Hi Alex,

    Thanks very much for this tutorial! I have a question regarding this paragraph’s quiz:

    You state that the obvious solution is:

    But I can’t really figure out why the minus signs are put before m_y and m_z. In my own version, I didn’t use these. Is this perhaps a copy-paste error, or am I missing the point?

    Your help is much appreciated!

    Kind regards,

    Eelco

Leave a Comment

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

  

  

  

2 × 1 =