C++

C++ : Overload Subscript [ ] operator

C++ provides a mechanism for overloading existing operators so that they can be used on objects of user-defined classes.
Consider the example of a String class for which the subscript ( [ ] ) operator has been overloaded.

Overload operator subscript [ ]
// Inside main ( )
{
      String obj (“EARTH”);
      char ch = obj [ 2 ];     // Resolved as => ch = obj . operator [ ] ( 2 )
      obj [ 0 ] = ‘D’;             // Resolved as => obj . operator [ ] ( 0 ) = ‘D’
}


Prototype ( not entirely suitable ) [ char String :: operator [ ] ( int ) ]
char operator [ ] ( int pos ) {
      assert ( pos >= 0 && pos < m_len );
      return * ( m_buff + pos );
}

The above code works fine for the below code statement
char ch = obj [ 2 ];

The above statement gets resolved as ch = obj . operator [ ] ( 2 );
In this statements, we are passing an integer to the function operator [ ] ( ). This integer specifies the index position from where the character can be fetched. The statement

return *(m_buff + pos);

returns the character at the specified index position. This character is then assigned to the character ch in the main function.
However, this prototype function does not work for the call obj [ 0 ] = ‘D’;. This call gets resolved as obj . operator [ ] ( 0 ) = ‘D’;.

As we see that, the operator function appears on the left hand side of the assignment operator. This function returns a character constant. What we are trying to do in the code is, we are assigning a character constant ‘D’ to some character constant returned by the prototype function.
This results in the compilation error

error: lvalue required as left operand of assignment

The above error indicates that the left hand side of the assignment operator does not have a memory location.



Correct prototype [ char& String :: operator [ ] ( int ) ]
char& operator [ ] ( int pos ) {
      assert ( pos >= 0 && pos < m_len );
      return * ( m_buff + pos );
}

In the above prototype, we are returning the character by reference. When the character is returned by reference, the statement obj [ 0 ] = ‘D’; does not give an l-value error.
This is because

  • When a function returns by reference and is on the left hand side of the assignment operator, the location (l-value) of the variable is returned instead of its value.
  • When a function returns by reference and is on the right hand side of the assignment operator, the value of the variable is returned.

Therefore by returning a reference to the character, this function becomes valid for both types of calls

char ch = obj [ 2 ];
obj [ 0 ] = 'D'; 

C++ program for a String class demonstrates the overloading of [ ] / subscript operator.

#include<iostream>
#include<cstring>
#include<cassert>

using namespace std;

class String {

    private:

    int m_len;
    char* m_buff;

    public:

    // Default constructor
    String () {
       m_len = 0;
       m_buff = new char;
       m_buff[0] = '\0';
    }

    // Parameterized constructor
    String (const char * str) {
       m_len = strlen(str);
       m_buff = new char[m_len + 1];
       strcpy(m_buff, str);
    }

    // Overloading of [] / subscript operator for String class
    char& operator [] (int pos) {
        assert(pos >= 0 and pos < m_len);
        return *(m_buff + pos);
    }

    ~String() {
       cout << "Destructor got called." << endl;
       if (m_buff) {
           delete [] m_buff;
       }
    }

    void Display() {
        cout << m_buff << endl;
    }
};

int main() {

   String s1("BLUE_EARTH");

   cout << "String s1 : ";
   s1.Display();

   char ch = s1[2];
   cout << "Character at pos 2 : " << ch << endl;

   s1[0] = 'G';
   cout << "After replacing the first character with 'G', String s1 : ";
   s1.Display();

   cout << "Main ends. Now returning" << endl;
   return 0;
}

Output

String s1 : BLUE_EARTH
Character at pos 2 : U
After replacing the first character with 'G', String s1 : GLUE_EARTH
Main ends. Now returning
Destructor got called.


Copyright (c) 2019-2024, Algotree.org.
All rights reserved.