The World of Mayukh Bose

<< Back to Main Page Mayukh's world: e-mail me | about
Mayukh's World: Operator Overloading With C++ Thursday, November 23, 2017
Index
  • Introduction
  • What Operators?
  • Rules
  • Assignment Operator
  • More on Assignment
  • Arithmetic Operators
  • Arithmetic with Globals
  • Increment/Decrement
  • Operator-Assignment
  • Unary Operators
  • Relational Operators
  • Bitshift/Extraction
  • Subscript Operator
  • Function Call Operator
  • Bit and Logical Ops
  • Comma Operator
  • Pointer to Member
  • new and delete Ops
  • Credits and Thanks
  • My Free Software
  • Delphi/C++ Builder
  • Pocket PC
  • FreeSpeech Chat
  • C/C++ Freebies
  • Perl
  • Python
  • Ruby
  • C++ Operator Overloading Tutorial e-mail me

    Subscript Operator []

    The subscript operator [] in C++ is normally used to reference a specific item in a group of items. Since the operator doesn't logically map to any operations of our complex class, we will define another class to illustrate how to overload the subscript operator.
          class IntArray {
          private:
            int *ptr;
          public:
            IntArray(size_t size) { ptr = new int[size]; }  
    	~IntArray() { delete [] ptr; }  
          };
    
          int main(void) {
            IntArray iArray(10); // Declare a 10 element array                            
    
            return 0;
          }
        
    Now we can overload the [] operator to reference elements within the IntArray object. Hence, we declare a member function within the class:
          class IntArray {
          private:
            int *ptr;
          public:
            IntArray(size_t size) { ptr = new int[size]; }  
    	~IntArray() { delete [] ptr; }
    	int& operator[](int index);
          };
        
    If you are wondering why this function returns a reference, note that there are two common ways to use the subscript operator:
          cout << iArray[0]; // This is a read operation.
          iArray[0] = 2;     // This is a write operation.
        
    As you can see, the second line above changes the value of the object and thus a reference should be returned for this scenario to work. We don't always need to return a reference though, as we shall see later on in this section. For now, we can implement the member function as follows:
          int& IntArray::operator[](int index){
            return ptr[index];
          }
        
    We can now test out this code:
          int main(void) {
            IntArray iArray(10); // Declare a 10 element array                            
    
    	// Write Operations
    	iArray[0] = 5; 
    	iArray[1] = 3;
    
    	// Read Operations
    	cout << iArray[0] << endl;
    	cout << iArray[1] << endl;
    
    	return 0;
          }
        
    Running this produces the expected output.

    The subscript operator overload takes only one argument, but it can be of any type. For instance, you could do this:
          const int SomeClass::operator[](const std::string& sArg)
        
    and get it to lookup a table for an entry that contains sArg in it. In the next section, we will study another operator that can handle multiple arguments of different types.

    In certain situations, we don't necessarily want to return a reference. For instance, there may be a need to make the object read-only (i.e.) you can only read a value, but not assign to it. In this case, we can overload the subscript operator a little differently:
          class IntArray {
          private:
            int *ptr;
          public:
            IntArray(size_t size) { 
              ptr = new int[size]; 
              for (size_t i=0; i < size; i++)
                ptr[i] = i;
            }
            ~IntArray() { delete [] ptr; }
            const int operator[](int index);
          };
    
          const int IntArray::operator[](int index) {
            return ptr[index];
          }
    
          int main(void) {
            IntArray iArray(10);
    
            cout << iArray[0] << endl;
            cout << iArray[1] << endl;
    
            //  iArray[0] = 5; // Causes a compile error.
    
            return 0;
          }
        
    Note that the body of the function is identical, but since we declared our subscript operator to return a value instead of a reference, any attempt to assign a value to it will cause a compile error.

    Exercises

    1. Our overloaded subscript operators do not check if the index requested is outside the array bounds or not. To fix this, add a member variable and note down the size of the array in the constructor. Then, in the overloaded functions, make sure that index is less than the array size. Throw an exception if this is not the case. Another variation of this could resize the array instead of throwing an exception.

    2. The default copy constructor generated by the compiler has a problem in it. It copies the pointer directly from one instance of an object to another, instead of making a copy of the data. This causes a problem because now there are two pointers pointing to the same memory and when one is destroyed, the other will point to freed memory. The solution is to write your own copy constructor that makes a copy of the data properly. Write a copy constructor to handle the data appropriately (or if you don't feel like doing this, be aware that a problem exists and don't use the above code in production!)


    <<Previous: Bitshift/Extraction Operators ^Up to Mayukh's World^ Next: Function Call Operator >>

    Copyright © 2004 Mayukh Bose. All rights reserved.
    This work may be freely reproduced provided this copyright notice is preserved.
    OPTIONAL: Please consider linking to this website (http://www.mayukhbose.com/) as well.