All of the overloaded operators you have seen so far let you define the type of the operator’s parameters, but not the number of parameters (which is fixed based on the type of the operator). For example, operator== always takes two parameters, whereas operator! always takes one. The parenthesis operator (operator()) is a particularly interesting operator in that it allows you to vary both the type AND number of parameters it takes.

There are two things to keep in mind: first, the parenthesis operator must be implemented as a member function. Second, in non-object-oriented C++, the () operator is used to call functions. In the case of classes, operator() is just a normal operator that calls a function (named operator()) like any other overloaded operator.

**An example**

Let’s take a look at an example that lends itself to overloading this operator:

1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Matrix { private: double data[4][4]; public: Matrix() { // Set all elements of the matrix to 0.0 for (int row=0; row < 4; ++row) for (int col=0; col < 4; ++col) data[row][col] = 0.0; } }; |

Matrices are a key component of linear algebra, and are often used to do geometric modeling and 3D computer graphics work. In this case, all you need to recognize is that the Matrix class is a 4 by 4 two-dimensional array of doubles.

In the lesson on overloading the subscript operator, you learned that we could overload operator[] to provide direct access to a private one-dimensional array. However, in this case, we want access to a private two-dimensional array. Because operator[] is limited to a single parameter, it is not sufficient to let us index a two-dimensional array.

However, because the () operator can take as many parameters as we want it to have, we can declare a version of operator() that takes two integer index parameters, and use it to access our two-dimensional array. Here is an example of this:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include <cassert> // for assert() class Matrix { private: double data[4][4]; public: Matrix() { // Set all elements of the matrix to 0.0 for (int row=0; row < 4; ++row) for (int col=0; col < 4; ++col) data[row][col] = 0.0; } double& operator()(int row, int col); const double& operator()(int row, int col) const; // for const objects }; double& Matrix::operator()(int row, int col) { assert(col >= 0 && col < 4); assert(row >= 0 && row < 4); return data[row][col]; } const double& Matrix::operator()(int row, int col) const { assert(col >= 0 && col < 4); assert(row >= 0 && row < 4); return data[row][col]; } |

Now we can declare a Matrix and access its elements like this:

1 2 3 4 5 6 7 8 9 10 |
#include <iostream> int main() { Matrix matrix; matrix(1, 2) = 4.5; std::cout << matrix(1, 2); return 0; } |

which produces the result:

4.5

Now, let’s overload the () operator again, this time in a way that takes no parameters at all:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
#include <cassert> // for assert() class Matrix { private: double data[4][4]; public: Matrix() { // Set all elements of the matrix to 0.0 for (int row=0; row < 4; ++row) for (int col=0; col < 4; ++col) data[row][col] = 0.0; } double& operator()(int row, int col); const double& operator()(int row, int col) const; void operator()(); }; double& Matrix::operator()(int row, int col) { assert(col >= 0 && col < 4); assert(row >= 0 && row < 4); return data[row][col]; } const double& Matrix::operator()(int row, int col) const { assert(col >= 0 && col < 4); assert(row >= 0 && row < 4); return data[row][col]; } void Matrix::operator()() { // reset all elements of the matrix to 0.0 for (int row=0; row < 4; ++row) for (int col=0; col < 4; ++col) data[row][col] = 0.0; } |

And here’s our new example:

1 2 3 4 5 6 7 8 9 10 |
#include <iostream> int main() { Matrix matrix; matrix(1, 2) = 4.5; matrix(); // erase matrix std::cout << matrix(1, 2); return 0; } |

which produces the result:

0

Because the () operator is so flexible, it can be tempting to use it for many different purposes. However, this is strongly discouraged, since the () symbol does not really give any indication of what the operator is doing. In our example above, it would be better to have written the erase functionality as a function called clear() or erase(), as `matrix.erase()`

is easier to understand than `matrix()`

(which could do anything!).

**Having fun with functors**

Operator() is also commonly overloaded to implement **functors** (or **function object**), which are classes that operate like functions. The advantage of a functor over a normal function is that functors can store data in member variables (since they are classes).

Here’s a simple functor:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class Accumulator { private: int m_counter = 0; public: Accumulator() { } int operator() (int i) { return (m_counter += i); } }; int main() { Accumulator acc; std::cout << acc(10) << std::endl; // prints 10 std::cout << acc(20) << std::endl; // prints 30 return 0; } |

Note that using our Accumulator looks just like making a normal function call, but our Accumulator object is storing an accumulated value.

You may wonder why we couldn’t do the same thing with a normal function and a static local variable to preserve data between function calls. We could, but because functions only have one global instance, we’d be limited to using it for one thing at a time. With functors, we can instantiate as many separate functor objects as we need and use them all simultaneously.

**Conclusion**

Operator() is sometimes overloaded with two parameters to index multidimensional arrays, or to retrieve a subset of a one dimensional array (with the two parameters defining the subset to return). Anything else is probably better written as a member function with a more descriptive name.

Operator() is also often overloaded to create functors. Although simple functors (such as the example above) are fairly easily understood, functors are typically used in more advanced programming topics, and deserve their own lesson.

**Quiz time**

1) Write a class that holds a string. Overload operator() to return the substring that starts at the index of the first parameter. The length of the substring should be defined by the second parameter.

Hint: You can use array indices to access individual chars within the std::string

Hint: You can use operator+= to append something to a string

The following code should run:

1 2 3 4 5 6 7 |
int main() { Mystring string("Hello, world!"); std::cout << string(7, 5); // start at index 7 and return 5 characters return 0; } |

This should print

world

9.10 -- Overloading typecasts |

Index |

9.8 -- Overloading the subscript operator |

matrix(1, 2) = 4.5;

how this sets value, i didn't understand.

please explain,

Thanks.

It calls `Matrix::operator()(int row, int col)`, which returns a `double&`. If you forgot about reference, re-read lesson 6.11 and 7.4a.

I have hard time figuring out why something really odd. Consider this code:

If you print that, you'll see that first element of strA and strB are 'H', but have different adresses (not surprising). Then however the second element of strA has the SAME adress as the first element of strB, but has different value: 'e' (which is also shared by the second element of strB). Then the third element of strA has the SAME adress as second element of strB, but again has different value 'l' (instead of 'e', which the second strB element has). And the fourth element of strA has the same adress as the third element of strB, but again different value.

So how is possible that one and the same adress holds different values for two variables of the same type? No assignement is done within the loop, so that to expect any overwrite action, only output statements! How is at all possible one and same adress to be allocated to two different array variables that are not reference to each other?

Line 9: You can't store more than 1 character in a char.

You're taking the address of `strA` and `strB`, which are `std::string`. This address isn't the address of the actual string. Pointer arithmetic on `std::string` uses `std::string`'s size. What you want is

`c_str` returns the C-style string.