|
Function Call Operator ()
The function call operator in C++ is the () operator. It can be overloaded similar to the subscript operator that
we examined previously, with one MAJOR difference. The subscript operator can accept only one argument,
whereas the function call operator can accept multiple arguments of varying types. This particular fact
is very significant to us.
For example, if we have a 2-dimensional array class, we cannot overload [] to reference a specific cell
of the array, since [] only takes one value as argument. However, we can overload the () operator, since
it can take multiple arguments, and therefore, we can specify a row and a column as arguments. In fact, the function
call operator is the ONLY overloaded operator that can take variable numbers and types of arguments. This
allows us to use (and misuse) it in a variety of situations.
For our example, we will build on the previous example and overload () to do the same thing as the [] operator. As it
happens, some languages (such as BASIC and FORTRAN) use () for array subscripting, so people are used to seeing () used
that way. We start by adding another member function
to the class.
class IntArray {
private:
int *ptr;
public:
IntArray(size_t size) { ptr = new int[size]; }
~IntArray() { delete [] ptr; }
int& operator[](int index);
int& operator()(int index);
};
The function implementation is pretty much identical to the previous page as well.
int& IntArray::operator()(int index){
return ptr[index];
}
As before, we can test this object as follows:
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 code produces the expected output.
As seen before in the previous page (subscript operator), it is not necessary to always
return a reference. For instance, if you wanted to make the object read only, you could make it return a const int
instead of an int& reference.
Exercises
1. Our overloaded operators do not check if the index is within the array bounds. Add code to do this and throw an exception
if needed. Another variation of this could be to resize the array as needed, 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.
3. Rewrite the class to handle two dimensional arrays. The following code should help you get started.
class TwoDArray {
private:
int rows, cols;
int *ptr;
public:
TwoDArray(size_t max_rows, size_t max_cols)
{
rows = max_rows; cols = max_cols;
ptr = new int[rows * cols];
}
~TwoDArray() { delete [] ptr; }
int operator()(int row, int col) const;
int& operator()(int row, int col);
};
int TwoDArray::operator()(int row, int col) const {
return ptr[row * rows + col];
}
// Implement the other function here
// Also implement a copy constructor, if you feel like it
Verify that this code works:
int main(void) {
TwoDArray iArray(10, 10); // Declare a 10x10 element array
iArray(0, 1) = 5;
iArray(1, 1) = 2;
cout << iArray(0, 1) << endl;
cout << iArray(1, 1) << endl;
return 0;
}
|
|