All of the overloaded operators you have seen so far let you define the type of the operator’s parameters, but the number of parameters is fixed based on the type of the operator. For example, the == operator always takes two parameters, whereas the logical NOT operator always takes one. The parenthesis 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-class C++, the () operator is used to call functions or write subexpressions that evaluate with higher precedence. In the case of operator overloading, the () operator does neither -- rather, it is just a normal operator that calls a function (named operator()) like any other overloaded operator.

Let’s take a look at a common 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 adData[4][4]; public: Matrix() { // Set all elements of the matrix to 0.0 for (int nCol=0; nCol<4; nCol++) for (int nRow=0; nRow<4; nRow++) adData[nRow][nCol] = 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[] only has one 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 integers 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 |
#include <cassert> // for assert() class Matrix { private: double adData[4][4]; public: Matrix() { // Set all elements of the matrix to 0.0 for (int nCol=0; nCol<4; nCol++) for (int nRow=0; nRow<4; nRow++) adData[nRow][nCol] = 0.0; } double& operator()(const int nCol, const int nRow); }; double& Matrix::operator()(const int nCol, const int nRow) { assert(nCol >= 0 && nCol < 4); assert(nRow >= 0 && nRow < 4); return adData[nRow][nCol]; } |

Now we can declare a Matrix and access it’s elements like this:

1 2 3 |
Matrix cMatrix; cMatrix(1, 2) = 4.5; std::cout << cMatrix(1, 2); |

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 |
#include <cassert> // for assert() class Matrix { private: double adData[4][4]; public: Matrix() { // Set all elements of the matrix to 0.0 for (int nCol=0; nCol<4; nCol++) for (int nRow=0; nRow<4; nRow++) adData[nRow][nCol] = 0.0; } double& operator()(const int nCol, const int nRow); void operator()(); }; double& Matrix::operator()(const int nCol, const int nRow) { assert(nCol >= 0 && nCol < 4); assert(nRow >= 0 && nRow < 4); return adData[nRow][nCol]; } void Matrix::operator()() { // reset all elements of the matrix to 0.0 for (int nCol=0; nCol<4; nCol++) for (int nRow=0; nRow<4; nRow++) adData[nRow][nCol] = 0.0; } |

And here’s our new example:

1 2 3 4 |
Matrix cMatrix; cMatrix(1, 2) = 4.5; cMatrix(); // erase cMatrix std::cout << cMatrix(1, 2); |

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 `cMatrix.Erase()`

is easier to understand than `cMatrix()`

(which could do anything!).

Operator () is commonly overloaded with two parameters to index multidimensional arrays, or to retrieve a subset of a one dimensional array (returning all the elements from parameter 1 to parameter 2). Anything else is probably better written as a member function with a more descriptive name.

9.10 -- Overloading typecasts |

Index |

9.8 -- Overloading the subscript operator |

Whew! It's getting more complicated

Hi..

In above example cMatrix is a class object and you have not overloaded << operator. still "std::cout << cMatrix(1, 2)" statement is working fine without error. how is it possible??

that is possible because the parenthesis operator in that class returns a reference to a built-in datatype "double" which of course has its own overloaded stream extraction operator.

Is there a way to make the overloading of the parenthesis operator work usefully, when dealing with dynamically allocated objects?

I did the overloading very similar to the way described here and the only way (that I found) to access my object is:

(*object)(x,y)

which looks quite ugly...

be more explanatory

Here's a noobish question:

Shouldn't it be

?

POD types should be passed by value and not pass by reference

Actually, he's right that something is wrong here. The "const" keyword does nothing, since POD gets passed by value. It makes more sense to write

Wikipedia has some more information about functors here, for anybody interested in learning more about them.

As I understand it, the basic idea of functors is that instead of passing a function pointer to a function to do a specific job, you pass a class with an overloaded () operator to do the same job. The advantage here is that classes can store information about the state of things, whereas functions can not.

Overloading () for doing functors is an advanced-level C++ concept, so don't sweat it if you're just learning the language. :)

I must say that functor callbacks is not perfect solution (actually, there is no such thing at all).

For caller implementation one have to use either known interface - a base class with virtual operator(), or use template.

This concept called "function objects" or "functors".

Functors in it's essence is C++ style callbacks.