Here are some examples and documentation. The callback implementations are called "bob" and "troll", are used indirectly (if need be) through "_bob" and "_troll" and are used in the function "jessica". The program should output 20.
There are several ways. One is through the old fashioned function pointer. http://www.newty.de/fpt/index.html Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
#include <iostream>
int bob() { return 13; }
int troll(int hmm) { return hmm + 2; }
int jessica(int (*_bob)(void), int (*_troll)(int), int hmm)
{
return _bob() + _troll(hmm);
}
int main()
{
std::cout << jessica(&bob, &troll, 5) << std::endl;
return 0;
}
|
Another is the templated "concept" ("concept" being the actual name of the concept). A little bit more complex but basically, using templates, you can have a unified interface into which a class can be passed as an abstract thing. This helps with interchangeability quite well. I suck at explanations, here's some code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
#include <iostream>
struct Test
{
int bob() { return 13; }
int troll(int hmm) { return hmm + 2; }
};
template <typename T>
int jessica(int hmm)
{
T tmp;
//Note that technically, you can use any class that implements bob() and troll(int).
//This is used quite a bit in the STL and other libraries such as Boost.
return tmp.bob() + tmp.troll(hmm);
}
int main()
{
std::cout << jessica<Test>(5) << std::endl;
return 0;
}
|
There's also the idea of interchangeable interfaces which are a bit more complicated but still kinda useful. They give a rather cool looking runtime solution. This concept uses something called a "virtual table". A virtual table is basically a pointer to a list of various functions. While the vtable pointer is often considered overhead, its 9.9/10 times neglible. http://www.parashift.com/c++-faq-lite/virtual-functions.html Example:
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
|
#include <iostream>
struct Test
{
virtual int bob() = 0;
virtual int troll(int) = 0;
};
struct ImplTest : public Test
{
virtual int bob() { return 13; }
virtual int troll( int hmm) { return hmm +2; }
};
//Note that I'm passing a pointer.
//You cannot instantiate the base class of an interface.
int jessica(Test* lol, int hmm)
{
return lol->bob() + lol->troll(hmm);
}
int main()
{
ImplTest ex; //Note that this is not of type Test.
std::cout << jessica(&ex, 5) << std::endl;
return 0;
}
|
Lets take one more example. Let's say I'm a game that wants to keep it's source secret and proprietary but I want some users to be able to define functions that are called on certain events. The game defines a function that lets you pass in callbacks.
The first solution works fine but it's often held in a struct, and not passed individually as it's both faster and more controlled.
The second solution will have tons of problems and probably will not work. The game interface has no way of knowing where your class is. As in, if you were to pass your class as a template, it will know the name of that template and it will attempt to call such a template, but it will not be able to find the implementation. Using explicit template instantiation, you can force this onto the game but only the game would be able to do this thus its not very useful in an interface.
The third solution dominates the second in C++, giving both a more object oriented solution and something more similar to (although ugly compared to normal) interfaces. The game will provide a base class of pure virtual functions for you to implement. You would then implement a sub class, allocate the class, cast it to a base class pointer, and then pass it. What you are passing essentially is the implementation of the base class, just a list of pointers to functions, very similar to a struct of pointers.
Hope this helps.