简体   繁体   中英

implementing prefix operator++

From http://www.learncpp.com/cpp-tutorial/97-overloading-the-increment-and-decrement-operators/

Class declaration

class Digit
{
private:
    int m_nDigit;
public:
    Digit(int nDigit=0)
    {
        m_nDigit = nDigit;
    }

    Digit& operator++();
    Digit& operator--();

    int GetDigit() const { return m_nDigit; }
};

Their implementation of operator++

Digit& Digit::operator++()
{
    // If our number is already at 9, wrap around to 0
    if (m_nDigit == 9)
        m_nDigit = 0;
    // otherwise just increment to next number
    else
        ++m_nDigit;

    return *this;
}

My alternate implementation of operator++

Digit& Digit::operator++()
{
    return Digit(m_nDigit == 9 ? 0 : (m_nDigit + 1));
}

I wanted to know

  1. if there are any downsides of creating a new object like I have done, and
  2. about how to choose one of these implementations?

There certainly are downsides to creating an object as you have done:

  1. It will not compile. It is impossible to bind a non-const reference to a temporary.

  2. Even if it did compile it would not perform the correct operation (your version makes operator++ set m_nDigit to 9 , the other version increments m_nDigit , wrapping around when 10 is reached).

  3. Even if it did compile and do the right thing, it would be very unsafe. The returned reference would be bound to a temporary object which would be destroyed before the function returned, this would mean that any attempt to access the object referenced by the return value of operator++ would result in undefined behaviour.

To choose between the two implementations, you should pick the one which compiles, is correct and is safe.

You have a problem with the ternary operator. Also you are returning a copy of the object not the object itself, and if you are trying to overload the operator to work like a built-in type, you should always return a reference to the object.

I think you should do it like this:

Digit& Digit::operator++()
{
    m_nDigit = (m_nDigit == 9 ? 0 : m_nDigit++);
    return *this;
}

Or like this:

Digit& Digit::operator++()
{
    m_nDigit = (++m_nDigit % 10);
    return *this;
}

The downside of creating a new object is that in code like:

Digit d;
++d;

I would expect the value of d to change and with a new object it doesn't. This operator is in many cases used like this (without assigning it to a variable) so if you don't increase and return the same object, you can't use it like that.

In your alternative implementation you have 2 issues:

  1. instead of m_nDigit = 9 do m_nDigit == 9 . Currently m_nDigit will always be 9, and the return value will always be 0.

  2. you're supposed to change the value of m_nDigit . When returning 0 - you don't.

The return statement is problematic because the operator is expected to change the value of the operand, not to create a new object.

edit

To clarify the problem, consider code:

Digit x;
x++;

What would you expect x to be as the result of this code? I would expect it to be 1. Using your operator, it remains unchanged.

  1. m_nDigit = 9 is an assignment and will always be evaluated to true .
  2. You return a copy of the object but return type is a reference. This may bite you (see Is returning a temp-object by reference possible ).
  3. Why not m_nDigit = (m_nDigit + 1) % 9; ?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM