Notes on Function Pointers
(related reading: Main & Savitch pp. 459-461, Wang pp. 146-147)Idea: treat functions like other objects
If we have a function foo with a prototype:
bool foo(int x, int y);we want to be able to say:
f = foo;for a suitable declaration of f and then use f wherever we might use foo.
Pointers to functions
f isn't really a function - it's a pointer to a function. Function pointers can be declared as:<return type> (* <var>)(<argument types>)as in:
bool (*f) (int, int);The notation looks like a function prototype, except *f appears in parentheses. Notation is a little confusing, but we can use typedefs to make it more clear:
typedef bool (* int_comparison_fun) (int,int);Now we can write:
int_comparison_fun f;
f = foo;
Functions as arguments to other functions
More important than assigning function pointer variables to point to various functions, we can use function pointers to pass functions as arguments into other functions. For example:void sort(int A[], size_t n, bool (*compare)(int,int))Using the typedef, this function can be declared as:
{
int min;
size_t k,minIndex;
for(k=0; k+1 < used; k++) {
minIndex = k;
min = data[k];
for(size_t j=k+1; j < used; j++) {
if (compare(data[j],min)) {
min = data[j];
minIndex = j;
}
}
data[minIndex] = data[k];
data[k] = min;
}
}
void sort(int A[], size_t n, int_comparison_fun compare);
Squaring a list of integers
We can make functions more parametric - and allow for more reuse, by passing functions as arguments. This works particularly well with iterators. For example, suppose we have a list of integers:ListWe would like to be able to write C++ code that will create a coresponding list of the squares of those integers:L;
Using external iterators we might write:
ListsquareList(const List L)
{
ListIteriter(L);
ListnewList;
for(; !iter.isEnd(); iter.advance()) {
int i = iter.current();
newList.append(i * i);
}
return newList;
}
New int lists from old
Now suppose we would like to create a list consisting of twice the corresponding values in the original list:Rather than rewriting code very similar to what we have written already, we can reuse the old code, by adding a function argument:
Listmap(const List L, int (*f)(int))
{
ListIteriter(L);
ListnewList;
for(; !iter.isEnd(); iter.advance())
newList.append(f(iter.current()));
return newList;
}
int square(int i) { return(i*i); }We can now write:
int dbl(int i) { return(2*i); }
map(L, square);
map(L, double);
A map function template
Finally, we can write a map function template so that it can be applied over lists of anything:templateNote the use of pointers in the return type to avoid redundant copy construction.
List* map(const List & source, T (*f)(T))
// maps a list to another list, applying f to each element
{
ListIteriter(source);
List*newList = new List ;
for(; !iter.isEnd(); iter.advance())
newList->append(f(iter.current()));
return newList;
}
No comments:
Post a Comment