Reading textbooks on programming, I am convinced that the perception of the material becomes much more complicated if the author submits himself to the concepts and tools, forgetting how important the context in which the material is revealed. And, at the same time, how natural and easy the understanding comes when you feel the real convenience of using a new tool.
In my opinion, function pointers are just such an example. The fact is that the syntax for declaring and using function pointers is not very obvious, especially for not-so-experienced programmers, and if you immediately “sprinkle” with details and syntactic possibilities, you won't see a forest behind the trees. In this post, I want to share my vision of pointers to functions and give a simple example, which I dare to hope, will please me with its ease and kill another hare - it will demonstrate a terrible monster called “polymorphic challenge”.
So, let us have an array of strings (although no one bothers it to be some other array) that needs to be sorted. Sort, not sort. That is, we plan to do this regularly and in different ways.
const int n = 15; string cities[n] = { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" };
Suppose we need to be able to sort alphabetically (up / down) and along the length of the string (up / down). In other cases it can be by height, by weight, by population, by salary. Of course, we could implement some sorting method and replicate it with a change in the comparison method. But, as we understand, there is duplication of the code with all the consequences arising from it.
')
But how could it be otherwise if we cannot pass a function as an argument to a sorting function? Or, after all, can we? This is where pointers to functions come in. This is exactly the tool that allows you to work with functions in the same way as with variables. Well, or almost the same.
So, here it is a function pointer. Meet:
typedef bool(*CompareFunction) (int i, int j);
Do not try to understand the syntax. Just know that after this command we can use the CompareFunction type to declare variable functions, albeit with a fixed signature. In our case, these should be logical functions with two integer arguments. As you might guess, these will be different ways of comparing. Here they are:
bool compareUp(int i, int j) { return cities[i] < cities[j]; } bool compareDown(int i, int j) { return cities[i] > cities[j]; } bool compareLengthUp(int i, int j) { return cities[i].length() < cities[j].length(); } bool compareLengthDown(int i, int j) { return cities[i].length() > cities[j].length(); }
Now put them in an array:
CompareFunction compares[] = {compareUp, compareDown, compareLengthUp, compareLengthDown};
And then create a sort function:
void sortCities(CompareFunction compare) { for (int i = 0; i < n - 1; i++) { int j_min = i; for (int j = i+1; j < n; j++) { if (<b>compare(j, j_min)</b>) { j_min = j; } } string temp = cities[i]; cities[i] = cities[j_min]; cities[j_min] = temp; } }
And what is there bold? This is a polymorphic call: the compare variable can be used to slip any comparison function, and the function being called will be determined dynamically, providing the required sorting method.
And finally, we need some simple user interface to test everything.
int _tmain(int argc, _TCHAR* argv[]) { setlocale(LC_ALL, "Russian"); for (;;) { int choice; cout << " : "; cin >> choice; sortCities(compares[choice]); printCities(); } system("pause"); return 0; }
Now everything is beautiful. One programmer stamps logical functions, the second - optimizes the sorting algorithm, and the third - works on the user interface usability. And no one bothers anyone - even duplication of code.
PS The printCities () function is virtual, its implementation falls to the reader.