0

I thought I'd try beefing up my C++ and OpenGL by looking at the recently-released Doom 3 source. Much learned so far, but I've hit a wall. The class detailed here has methods

float  operator[] (int index) const  

and

float &  operator[] (int index) 

whose bodies both read

return ( &x )[ index ];

where x is one of the class' two data members (the other being y; this class is for 2-vectors).

While I can understand the syntax of each version's header/prototype, I don't get why they're both present.

const seems to appear (or not appear, as preferred) only to distinguish the headers sufficiently to allow compilation. (That is, remove const and VS2010 refuses to compile, similarly if both headers end in const.)

And why return a ref to a float? None of the class' seven other float-type methods do this, so I'm guessing efficiency isn't a factor (tho' maybe this operator's called vastly more often than the others).

Appreciate any insight as to what's going on here...

  • I'm sure you'll get better answers, but quickly: The first method is `const` to allow you to access the members for a vector that's `const` (i.e. read but not write). The other method allows you to modify the members for a vector that's not `const` (i.e. the reference allows you to read and write). – ta.speot.is Jan 14 '12 at 00:53
  • possible duplicate of [Operator overloading](http://stackoverflow.com/questions/4421706/operator-overloading) – sbi Jan 14 '12 at 09:32

4 Answers4

7

This is a common idiom (known as "const overloading"). See the C++ FAQ: http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.12.

The ambiguity is resolved by whether *this is const or not. On a const object, the const overload is called, in which case it acts in a read-only style. On a non-const object, the non-const is called, in which case it acts in a read/write style.

Note, crucially, that this is not a way of distinguishing between read and write accesses.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • I have the sudden urge to standard-quote this answer into hell, but alas, it's the only sensible way to explain it to non-standardese speakers. :) Also, what @Kerrek said. Cv-qualification on `this` would be `X* cv`, while it's `cv X*` (see §9.3.2/1). – Xeo Jan 14 '12 at 01:57
  • For the interested, [this answer](http://stackoverflow.com/a/8610728/500104) goes into some of the details on how overload resolution works. It's a fairly complicated process, so prepare yourself. :) It also explains some stuff about `*this`, and why the overload resolution isn't based on that (hint: `this` only exists inside a non-static member function). – Xeo Jan 14 '12 at 02:31
  • Thanks Oli, Xeo. Now, who on earth is this KerrekSB?! – user1148739 Jan 14 '12 at 03:33
1

Think of them as a related pair of getter and setter methods for subscripted elements. The float & operator[](int index) is the setter version and allows you to use syntax like so:

theObject[anIndex] = 1.0;

This requires that theObject is available to you as a non-const object (or through an Object * or Object &).

hypercode
  • 488
  • 2
  • 10
0

In the case without const, you are using a reference because you want to change the value when calling the function. Eg setting a value: a[11] = 5.0;

The case with const is added because other functions can only be declared as const functions if all other functions that they call are also const functions.

johanvdw
  • 401
  • 3
  • 11
0

And why return a ref to a float?

The reason to return a reference to a float is to allow the caller to modify that float. (By the way, efficiency wouldn't be a reason for this, since pointers tend to be at least as big as floats, so the extra indirection is pure cost.)

const at the end of a method signature indicates that it can safely be called on a const object/reference/expression. So, if v is an idVec2, then v[0] may be used as an lvalue (and v[0] = 3.0f will actually set v[0]), but if v is a const idVec2, then v[0] can only be used as an rvalue (meaning that v[0] = 3.0f is ilegal).

ruakh
  • 175,680
  • 26
  • 273
  • 307