c++ two versions of overloading subscript operator

11,302

Solution 1

A member function declaration with const at the end of it allows that function to be called even on a const object. This only makes sense for member functions that don't modify the state of the object.

Let's say the class you have that overloads these operators is called X. Presumably it behaves a bit like a container, giving access to the elements it contains through this operator[].

Now let's say the user wants to use a const X:

const X x = /* fill it */;
use(x[0]);

Should the user be allowed to do this? Probably. If they want a container that is immutable, then let them have it. If you didn't provide the const version of operator[], they wouldn't be able to do this. They're not trying to modify the container after all, they're just looking at its contents.

Now why make the const version of operator[] return a const reference? Because it has to. It's returning a reference to a member of the class itself. If the container was const and returned a non-const reference, the caller would be able to modify its internals just by using this operator:

const X x = /* fill it */;
x[0].modify();

Oh dear, we modify the state of x even though it's const. This would be bad and in fact, the compiler won't even let you do it.

Solution 2

Those are member functions of a class, and the version will be chosen based on whether that class in used as a const context.

This version will be called when [] is used on a object in a const context. It preserves the const-ness of the returned element.

const T& operator[](const int nIndex) const;

This version will be called when [] is used on a non-const object. It specifies that when your object isn't const, you'll get an element that you can modify, allowing code like myObject[0] = 10;

T& operator[](const int nIndex);

Solution 3

If the object you're accessing is const, you don't want to be able to modify it. The compiler wouldn't let you call the non-const version of the function.

const vector<int> mints;

mints[3] = 5; // not allowed by compiler

Solution 4

The first one

const T& operator[](const int nIndex) const;

is a constant method(function) ie it guarantees that it would not change any of the class member variable(unless its mutable).

It also returns a constant object which means you can call only constant function i.e you can call only functions that have const at the end similar to the one above.

T& operator[](const int nIndex);

This method may change the member variables and returns an object that can call any class methods.

We need them both because the constant object would be using the constant method and non constant would be using the other one.

Share:
11,302
Simon Righley
Author by

Simon Righley

Updated on June 05, 2022

Comments

  • Simon Righley
    Simon Righley almost 2 years

    My question is about the difference between:

    const T& operator[](const int nIndex) const;
    

    and:

    T& operator[](const int nIndex);
    

    Why would I need both of them defined in a class, what's the purpose? Wouldn't the latter suffice?

  • Dmitry Galchinsky
    Dmitry Galchinsky about 11 years
    I would add that 2 similar overloaded methods (const and non-const) is an often boilerplate in C++
  • Simon Righley
    Simon Righley about 11 years
    @sftrabbit: silly follow-up: Do I understand correctly that still I need to define two separate bodies of the const and non-const versions of the operators, and that these bodies will be exactly the same? Basically, smth like return MyDataStructure[nIndex]?
  • Joseph Mansfield
    Joseph Mansfield about 11 years
    @SimonRighley Yes, you'll need to define both of them. You could define the non-const version in terms of the const version but then you'd have to do a const_cast. You're better off just having the duplicate implementation.