The subscript operator [] is commonly defined to access and modify a data field or an element in an object.

In C++, the pair of square brackets [] is called the subscript operator. You have used this operator to access array elements and the elements in a string object and a vector object. You can overload this operator to access the contents of the object if desirable. For example, you may wish to access the numerator and denominator of a Rational object r using r[0] and r[1].

We first give an incorrect solution to overload the [] operator. We will then identify the problem and give a correct solution. To enable a Rational object to access its numerator and denominator using the [] operator, define the following function header in the Rational.h header file:

int operator[](int index);

Implement the function in Rational.cpp as follows:

1 int Rational::operator[](int index) <—— Partially correct
2 {
3
if (index == 0)
4
return numerator;
5
else
6       return denominator;
7 }

The following code

Rational r(2, 3);

cout << “r[0] is ” << r[0] << endl;

cout << “r[1] is ” << r[1] << endl;

displays

Can you set a new numerator or denominator like an array assignment such as the following?

r[0] = 5;

r[1] = 6;

If you compile it, you will get the following error:

In C++, Lvalue (short for left value) refers to anything that can appear on the left side of the assignment operator (=) and Rvalue (short for right value) refers to anything that can appear on the right side of the assignment operator (=). How can you make r[0] and r [1] an Lvalue so that you can assign a value to r[0] and r[1] ? The answer is that you can define the [] operator to return a reference of the variable.

int& operator[](int index);

Implement the function in Rational.cpp:

int& Rational::operator[](int index) <————- Correct

{

if (index == 0)

return numerator;

else

return denominator;

}

You are familiar with pass-by-reference. Return-by-reference and pass-by-reference are the same concept. In pass-by-reference, the formal parameter and the actual parameter are aliases. In return-by-reference, the function returns an alias to a variable.

In this function, if index is 0, the function returns an alias of variable numerator. If index is 1, the function returns an alias of variable denominator.

Note that this function does not check the bounds of the index. In Chapter 16, you will learn how to revise this function to make your program more robust by throwing an exception if the index is not 0 or 1.

The following code

1 Rational r(2, 3);
2 r[
0] = 5; // Set numerator to 5
3 r[1] = 6; // Set denominator to 6
4 cout << “r[0] is ” << r[0] << endl;
5 cout <<
“r[1] is ” << r[1] << endl;
6 cout <<
“r.doubleValue() is ” << r.doubleValue() << endl;

displays

In r[0], r is an object and 0 is the argument to the member function []. When r[0] is used as an expression, it returns a value for the numerator. When r[0] is used on the left side of the assignment operator, it is an alias for variable numerator. So, r[0] = 5 assigns 5 to numerator.

The [] operator functions as both accessor and mutator. For example, you use r[0] as an accessor to retrieve the numerator in an expression, and you use r[0] = value as a mutator.

For convenience, we call a function operator that returns a reference an Lvalue operator. Several other operators such as +=, -=, *=, /=, and %= are also Lvalue operators.

Source: Liang Y. Daniel (2013), Introduction to programming with C++, Pearson; 3rd edition.