On the use (and usefulness) of a pointer to member function vs directly calling the member function
I am new to pointer to member functions, and I would like to know their pros and cons.
Specifically, consider this:
#include <iostream>
#include <list>
using namespace std;
class VariableContainer;
class Variable
{
public:
Variable (int v) : value (v), cb_pointer (0) {}
~Variable () {}
void SetCallback (void (VariableContainer::*cb)(int)) {
cb_pointer = cb;
}
void FireCallback (开发者_JS百科void) {
/* I need a reference to a VariableContainer object! */
}
private:
int value;
void (VariableContainer::*cb_pointer) (int);
};
class VariableContainer
{
public:
VariableContainer () {}
~VariableContainer () {}
void AddVar (Variable &v) {
v.SetCallback (&VariableContainer::Callback);
}
void Callback (int v) { cout << v << endl; }
};
int main ()
{
Variable v (1);
VariableContainer vc;
vc.AddVar (v);
v.FireCallback();
return 0;
}
As stated in the comment, to trigger the callback (FireCallback
) I need some reference to an existing VariableContainer
object, which should be provided as an additional argument of VariableContainer::AddVar (...)
.
Now:
- Should I use the pointer to member function? Or should I call directly
Callback (...)
(since I have a pointer to theVariableContainer
object)? - What are the advantages and drawbacks of each solution?
TIA, Jir
Depending on what will vary in the future, you can decide:
- Other functions will be called by the variable's FireCallback => a pointer-to-mf may be useful, but other mechanisms are more c++ish
- Only the 'Callback' function is going to be called => stick with calling
arg->CallBack()
directly.
A possible solution to the problem is using an interface layer: this is no more than an implementation of the Observer pattern. This is a little more OO, hence verbose, but the syntax is way easier.
class Observer {
public:
virtual ~Observer(){};
virtual void callback( int v ) = 0;
};
// actual implementation
class MyCallbackObserver : public Observer {
virtual void callback( int v ) { std::cout << v << std::endl; }
void some_other_method( int v ) { std::cout << "other " << v ; }
};
And your Variable
class would have a container full of observers:
class Variable {
public:
std::vector<Observer*> observers; // warning: encapsulation omitted
void FireCallback(){
// assuming C++ 0x
for( auto it : observers ) {
(*it)->Callback( value );
}
}
If other functions need to be called on the same object, you may introduce a wrapper:
class OtherCaller: public Observer {
public:
MyObserver* obs;
virtual void callback( int v ) { obs->some_other_method( v ); }
}
And add it to the collection:
Variable var;
MyObserver m;
OtherCaller mo;
mo.obs = &m;
var.observers.push_back(&m);
var.observers.push_back(&mo);
var.FireCallback();
It depends on what your needs are here.
If you only have one callback function, and you always know its name, you might as well call it directly. It's simpler, easier to understand, and doesn't get extra variables involved.
Member function pointers would come in useful if you need the ability to call one of several callbacks depending on configuration: You would set the callback member function pointer to the actual callback you wish to call, and then that is used to select which callback to execute.
精彩评论