With a standard C-style string, you can use brackets to access individual characters:
char city[40] = "Amsterdam";
cout << city[0] << endl; // display the letter A
In C++ the two bracket symbols constitute a single operator, the bracket operator, and you can overload this operator by using a method called operator[]()
. Typically, a binary C++ operator (one with two operands) puts the operator between the two operands, as in 2 + 5
. But the bracket operator places one operand in front of the first bracket and the other operand between the two brackets. Thus, in the expression city[0]
, city
is the first operand, []
is the operator, and 0
is the second operand.
Suppose that opera
is a String
object:
String opera("The Magic Flute");
If you use the expression opera[4]
, C++ looks for a method with this name and signature:
String::operator[](int i)
If it finds a matching prototype, the compiler replaces the expression opera[4]
with this function call:
opera.operator[](4)
The opera
object invokes the method, and the array subscript 4
becomes the function argument.
Here’s a simple implementation:
char & String::operator[](int i)
{
return str[i];
}
With this definition, the statement
cout << opera[4];
becomes this:
cout << opera.operator[4];
The return value is opera.str[4]
, or the character 'M'
. So the public method gives access to private data.
Declaring the return type as type char &
allows you to assign values to a particular element. For example, you can use the following:
String means("might");
means[0] = 'r';
The second statement is converted to an overloaded operator function call:
means.operator[][0] = 'r';
This assigns 'r'
to the method’s return value. But the function returns a reference to means.str[0]
, making the code equivalent to
means.str[0] = 'r';
This last line of code violates private access, but because operator[]()
is a class method, it is allowed to alter the array contents. The net effect of the code is that "might"
becomes "right"
.
Suppose you have a constant object:
const String answer("futile");
Then, if the only available definition for operator[]()
is the one you’ve just seen, the following code is labeled an error:
cout << answer[1]; // compile-time error
The reason is that answer
is const
, and the method doesn’t promise not to alter data. (In fact, sometimes the method’s job is to alter data, so it can’t promise not to.)
However, C++ distinguishes between const
and non-const
function signatures when overloading, so you can provide a second version of operator[]()
that is used just by const String
objects:
// for use with const String objects
const char & String::operator[](int i) const
{
return str[i];
}
With the definitions, you have read/write access to regular String
objects and read-only access to const String
data:
String text("Once upon a time");
const String answer("futile");
cout << text[1]; // ok, uses non-const version of operator[]()
cout << answer[1]; // ok, uses const version of operator[]()
cin >> text[1]; // ok, uses non-const version of operator[]()
cin >> answer[1]; // compile-time error
3.14.144.229