Domanda

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.

È stato utile?

Soluzione

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; }

Altri suggerimenti

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.

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.

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++ ();

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top