6

I'm reading through "SAMS Teach Yourself C++ in 21 days" and I came across an example that I can't seem to understand:

#include<iostream>

using namespace std;

class Counter
{
  public:
    Counter() {itsVal=0;}
    const Counter& operator++ ();
    int GetItsVal() {return itsVal;}
  private:
    int itsVal;
};

const Counter& Counter::operator++()
{
  ++itsVal;
  return *this;
}

int main()
{
  Counter i;
  Counter a = ++i;
  cout << "a: " << a.GetItsVal() << " i: " << i.GetItsVal() << endl;
  ++a;
  cout << "a: " << a.GetItsVal() << " i: " << i.GetItsVal() << endl;
}

Why is there an "&" in the declaration of the ++ operator? I understood this to mean that the return type of the ++ operator was a reference, but it doesn't appear to be a reference to i (since incrementing a does not increment i). I've noticed the code returns the same result if I remove both "&", but maybe it's not as efficient.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
random_forest_fanatic
  • 1,232
  • 1
  • 12
  • 30

4 Answers4

6

In C++, when you create a reference, it's a proxy for the original object:

int i = 0;
int& a = i;

++i;
std::cout << i << " " << a << "\n"; // prints '1 1'

++a;
std::cout << i << " " << a << "\n"; // prints '2 2'

Now, in your case:

  • operator++ returns a reference to the current object
  • Counter a = ++i; creates a new object (no & after Counter) initialized as a copy of the reference to i

If you wish a to refer to i, you need to change its declaration:

Counter& a = ++i;
       ^

This will fail to compile thought because the return value of Counter::operator++ is Counter const&: you need to remove the const here which is non-idiomatic for operator++ and thus:

Counter& Counter::operator++() { ++itsVal; return *this; }
Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
2

Many functions have commonly observed patterns for their return values and general behavior, allowing you to easily and naturally use them.

Pre-increment and Pre-decrement operators always return a reference to the object after performing their task for chaining:

Counter& Counter::operator++()
Counter& Counter::operator--()

While Post-increment and Post-decrement operators either do not return any value, or a temporary containing the old value for easily copied value-types:

Counter Counter::operator++(int)
Counter Counter::operator--(int)

Or

void Counter::operator++(int)
void Counter::operator--(int)

It looks like in your example someone didn't follow common practice.

jrok
  • 54,456
  • 9
  • 109
  • 141
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
  • 1
    I think you've got descriptions for post/pre wrong, don't you? – jrok Apr 07 '14 at 13:04
  • @jrok: Never can rememeber which to call post and which pre. Everything else should be right, now you added some -- signs. – Deduplicator Apr 07 '14 at 13:05
  • Post- versions have got an `int` "postfix" in the signature, that's how I memorized it. – jrok Apr 07 '14 at 13:07
  • @Deduplicator Prefix increment operator declaration is similar to simple unary plus operator: `X& operator++();` vs `X operator+();`. And in the code: `a = ++b;` vs `a = +b;` (operator is placed before operand, *pre-*). Postfix one is (not too, in fact, but...) similar to binary plus operator: `X operator++(int);` vs `X operator+(int);` (a possible variant for some classes). And in the code: `a = b++;` vs `a = b + 1;` (operator is placed after [first] operand, *post-*). Maybe it can help to remember. – Constructor Apr 07 '14 at 13:34
0

To make you understand this easily, consider assignment operator overloading.


Counter& operator = (const Counter& RHS);

Counter a(10), b(20), c, d;

Now,

c = d = a is possible. When you return something as reference, that overloaded call can be used as R-Value.

Sivaraman
  • 438
  • 2
  • 9
  • So, if I understand correctly, returning a reference would allow me to use the returned value to change the value referred to, right? But, that's not what's happening in this example, is it? – random_forest_fanatic Apr 07 '14 at 12:32
0

Consider this:

void someFunction(const Counter& c);
void someFunction(Counter& c);

...

{
  Counter myCount = makeACounter();
  while(myCount.stillCounting()) {
    someFunction(++myCounter);
  }
}

someFunction() takes a reference so the last thing you want to do it make a copy of myCounter since that's potentially inefficient. Further, if someFunction's non-const variant is chosen (it will be in this case), passing a copy would be logically wrong since someFunction may legally modify the state of its argument and you'd expect to see that change in myCounter when the function returns.

Because of the above situation (and others), operator++ should return a non-const reference to *this (you just modified *this, so it can't be const can it?)

thus the method signature should be: Counter& operator++ ();

Sebastian Mach
  • 38,570
  • 8
  • 95
  • 130
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
  • Simple: Markdown syntax is supported and encouraged here, Stack Overflow does the coloring of code regions. You may want to `edit` your answer in order to see my changes. – Sebastian Mach Apr 07 '14 at 12:58