Language Selector

9.8 — Overloading the subscript operator

When working with arrays, we typically use the subscript operator ([]) to index specific elements of an array:

However, consider the following IntList class, which has a member variable that is an array:

Because the m_anList member variable is private, we can not access it directly from cMyList. This means we have no way to directly get or set values in the m_anList array. So how do we get or put elements into our list?

Without operator overloading, the typical method would be to create access functions:

While this works, it’s not particularly user friendly. Consider the following example:

Are we setting element 2 to the value 3, or element 3 to the value 2? Without seeing the definition of SetItem(), it’s simply not clear.

A better solution in this case is to overload the subscript operator ([]) to allow access to the elements of m_anList. The subscript operator is one of the operators that must be overloaded as a member function. In this case, our overloaded subscript will take one parameter, an integer value that is the index of the element to access, and it will return an integer.

Now, whenever we use the subscript operator ([]) on an object of our class, the compiler will return the corresponding element from the m_anList member variable! This allows us to both get and set values of m_anList directly:

In this case, it’s much more obvious that cMyList[2] = 3 is setting element 2 to the value of 3!

Why operator[] returns a reference

Let’s take a closer look at how cMyList[2] = 3 evaluates. Because the subscript operator has a higher precedence than the assignment operator, cMyList[2] evaluates first. cMyList[2] calls operator[], which we’ve defined to return a reference to cMyList.m_anList[2]. Because operator[] is returning a reference, it returns the actual cMyList.m_anList[2] array element. Our partially evaluated expression becomes cMyList.m_anList[2] = 3, which is a straightforward integer assignment.

In the lesson a first look at variables, you learned that any value on the left hand side of an assignment statement must be an l-value (which is a variable that has an actual memory address). Because the result of operator[] can be used on the left hand side of an assignment (eg. cMyList[2] = 3), the return value of operator[] must be an l-value. As it turns out, references are always l-values, because you can only take a reference of variables that have memory addresses. So by returning a reference, the compiler is satisfied that we are returning an l-value.

Consider what would happen if operator[] returned an integer by value instead of by reference. cMyList[2] would call operator[], which would return the value of cMyList.m_anList[2]. For example, if m_anList[2] had the value of 6, operator[] would return the value 6. cMyList[2] = 3 would partially evaluate to 6 = 3, which makes no sense! If you try to do this, the C++ compiler will complain:

C:VCProjectsTest.cpp(386) : error C2106: '=' : left operand must be l-value

Rule: Values returned by reference or pointer can be l-values or r-values. Values returned by value can only be r-values.


The subscript operator is typically overloaded to provide access to 1-dimensional array elements contained within a class. Because strings are typically implemented as arrays of characters, operator[] is often implemented in string classes to allow the user to access a single character of the string.

One other advantage of overloading the subscript operator is that we can make it safer than accessing arrays directly. Normally, when accessing arrays, the subscript operator does not check whether the index is valid. For example, the compiler will not complain about the following code:

However, if we know the size of our array, we can make our overloaded subscript operator check to ensure the index is within bounds:

In the above example, we have used the assert() function (included in the cassert header) to make sure our index is valid. If the expression inside the assert evaluates to false (which means the user passed in an invalid index), the program will terminate with an error message, which is much better than the alternative (corrupting memory). This is probably the most common method of doing error checking of this sort.

9.9 -- Overloading the parenthesis operator
9.7 -- Overloading the increment and decrement operators

36 comments to 9.8 — Overloading the subscript operator

  • sergk

    Backwards compatibility with C sometimes could be regretting.
    Subscript operator is such case. In C is meant to be used with C “arrays”, and in turn those are just `pointer+offset*sizeof` syntactic sugar.
    Long story short, handy `operator[]` is useless when you deal with pointer to an object. Of course there is possibility to use dereference operator, or just call `operator[]` explicitly, but this is no way better than using getters/setters.

    Such semantical inconsistency could lead to some evil pitfalls. Consider:

    class Node
    Node* m_list;
    Node* operator[] (const int index) { return m_list[index]; }

    and when usage:

    Node cMyNode;
    Node* pMyNode = cMyNode[2]; // ok - operator[]
    Node* pNoNode = pMyNode[2]; // gotcha!

  • Good point, Sergk. If you use a subscript on a pointer, the compiler will assume that you are trying to access a member of an array that the pointer is pointing to.

    If you want to use an overloaded subscript operator on the variable that a pointer points to, you have to dereference the pointer first. However, because the array index operator has a higher precedence than the subscript operator, you have to use parenthesis to make sure it resolves correctly:

    Node *pNode = new Node();
    cout << (*pNode)[2]; (dereference first, then use overloaded subscript operator to get second element)

  • jarves

    what about overloading the subscript operator to… say sort and int of arrays:


    class Whatever
    int * m_value;
    int &operator[](std::size_t index);

    • I am not sure what you are saying, Jarves. You want to overload the subscript operator to do what?

      • jarves

        oh sorries :S basically what i’m trying to do here is take a dynamic array of ints (int * m_value) and use the overloaded subscript operator to sort the array from smallest integer to highest integer… and it’s kickin my ass.

        • I would highly recommend using a function named Sort instead of overloading the subscript operator to do array sorting. It’s generally not a good idea to overload operators to do things they aren’t normally used for, simply because it’s confusing and non-intuitive.

          • jarves

            if i had a choice i would… but my professor is strict… and i been pounding my head on this keyboard for too long.. i mean he wants it done this way but your right a sort function would be sooo freakin easy…

  • davidv

    The “Why operator[] returns a reference” part was brilliant. You made a pretty difficult idea (at least to me) to seem obvious.

  • subs script operator overloading in c++ with header file include simple and sweet program dijiye

  • Mojito

    Hi, and thanks for this post.

    I have another question. I want to do sub-indexing too, something like: MyNewType[a][b].

    anybody? :)

  • rob

    Hi Alex,

    In a case where we have 2 lists, can we still overload the [] operator?
    How does the overload function know which list to use when returning the reference?


    • Jeffrey Bosboom

      Your operator[] function will do whatever you write in its body -- it’s just a regular member function with a funny name. So you can overload operator[] to return an element from the first list or the second list. You can also do something more complicated like:

      This will return an element from the first list if the index is 0-9, return an element from the second list if the index is 10-19, or throw an exception otherwise.

  • Nathan_OR

    Great explanation and yes thank you for the “why operator[] returns a reference” portion, it makes it very clear why it must be so when using array[n] as an l-value. However I am still not clear why operator[] returns a reference when used as an r-value! It seems that would be equivalent to:

    int x = 1;
    int y = 2;
    int array[3] = { 0, 0, 0 };

    array[0] = x; // okay, per your explanation, we don't mean to write 0 = 1, rather, we mean [element at index 0] = 1
    // but then what about:
    x = array[0]; // why does x end up holding the r-value of "0", instead of the address of the integer array element at index 0?

    Perhaps I need more coffee, but the reasoning here is escaping me… is it simply a matter of compiler convention that a reference used as an r-value will always be evaluated for its r-value rather than the l-value?

  • venkatvb

    why can’t we overload array subscript operator as friend. why it gives error when I overload [],->,= operator as friend?

  • kekie

    In the example, when you;

    IntList cMyList;
    cMyList[2] = 3;

    How does C++ know that the 2 is assigned to nIndex?
    Is just built-in that when overloading `[]` the argument comes from between `[` and `]` ?

  • senjes

    What will happen when I have array of objects and the subscript operator overloaded. I tried it , It is trying to invoke the equal to operator which I feel is correct . In this case, If I have array of objects then the subscript operator overloading is ignored right. Is there any workaround for this ?

  • blank

    The code below was to overload the [] operator to accept a list of 2 elements to access an element of
    a 3×3 matrix. It seems to work when I uses a variable assignment for the argument ie. “Indexer” , but will not work
    when I try to enter the list in the form of cAmatrix[{1,1}]. Is there a way I have [] operator take either inputs and output the same result?



  • Janez

    Would it be possible to exploit return by pointer to a private member of a class? Since we can’t access private members directly, we don’t know what is their address. But by returning a pointer to them, this would no longer hold true. Any problems that might come with that?

  • Rob G

    I’m surprised no one has pointed out that it is generally best to define two such operators:

    This ensures that use on the rhs of an expression does not confuse the compiler into thinking that the array may change.

  • anvekar

    In this are we not violating the encapsulation rule of private member, because as we are passing the reference to the original private member "m_anList[10]" i.e. in the main() we get "cMyList.m_anList[2] = 3". So we are just setting the value of the private member in the main() directly without using mutator. So this violates the rule.

    • Alex

      No, there’s no violation of encapsulation in providing direct access to a single integer via an overloaded operator[].

      If we changed the underlying implementation (from an array to a tree, for example), we could still pass back an integer reference to wherever element #2 mapped to in that new structure, and the code using this class would still function without modification.

      Encapsulation would be violated if we provided a method that returned m_anList, because that would expose the underlying data structure.

  • Pablo

    For the example with an array, I noticed you can use return by reference with a function as well, so you can do something like

    which does not have the clarity problem mentioned above. My question is: what is the need for overloading the [] operator then? Just having a more familiar way to work with your class?


  • If my class has 2 arrays of some type (as member), how can I overload the subscript operator to access different elements of both arrays:

    And, isn’t it a good idea (for C++ 11 users, and for int arrays) to initialize the arrays with all elements set to 0 like this:

    • Alex

      First, there’s a couple ways you could do this:

      * Overload the [] operator so that 0 = m_array1, and 1 = m_array2. Then you can do this: myObject[0][5]; // get the 5th element of m_array1
      * Overload the () operator and use two parameters, the first to select the array and the second to select the element

      Second, yes, it’s a good idea to initialize the arrays to zero.

      • Yup, I tried the second one and that worked. I was just too quick to ask this question :-)

      • Kiran C K

        Can you please include an example for the first method? Thanks in advance

        • Alex

          Sorry, I’m not following what you’re asking for an example for. Can you be more specific?

          • Kiran C K

            Can you please include an example for overloading [] with 2 or more member arrays in a class?
            You have mentioned the method: Overload the [] operator so that 0 = m_array1, and 1 = m_array2. Then you can do this: myObject[0][5]; // get the 5th element of m_array1. I am getting syntax errors while doing it. I think I am missing something which I am not sure, in my code.

            • Alex

              I’ll add an example when I get around to updating this article. In the meantime, make sure your overloaded operator[] is returning an array (either a pointer to a built-in array, or a reference to an array class such as std::array or std::vector).

  • Kiran C K

    #include <iostream>
    #include <cassert>
    class Digit
        int digit1[3]{0};

        int& operator[](const int index);

        ostream& operator<<(ostream& out);

    int& Digit::operator[](const int index)
        return digit1[index];

    std::ostream& Digit::operator<<(std::ostream& out)
        int loop;
        out << "{";
        for (loop = 0; loop < 3; loop++)
            out << digit1[loop] << " ";
        out << "}";

        return out;

    int main()

        Digit n;
        n[0] = 4;
        n[1] = 3;
        n[2] = 4;

        n << std::cout;

        return 0;

    In the above example, the "ostream does not have a type" error occurs only when the member variable is an array. Whereas when I add namespace it works. Is there any reason that it works only if we add std namespace for member arrays?

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter




seventeen − 11 =