I have a button class. I want the button class's constructor to take the function it will call when the button is pressed. This would be easy if the button class was only taking a function from one class, but the purpose of the button's constructor taking a function is that no matter what class the button is created in it will be able to store a pointer to a function in the class it's created in.
To illustrate:
struct Button {
Button(void (*functionPtr)()) {
// Store the function pointer to be called later
}
};
struct SomeClass {
void LoadFile();
SomeClass() {
Button* temp1 = new Button(&LoadFile); // ???
}
};
struct AnotherClass {
void SaveFile();
SomeClass() {
Button* temp2 = new Button(&SaveFile); // ???
}
};
How can I make that work?
A pointer-to-function and a pointer-to-member-function, despite seeming pretty similar, are actually entirely different beasts.
void (*functionPtr)()
is a pointer to a function that takes no arguments and returns void. &AnotherClass::SaveFile
is a pointer to a member function of AnotherClass
... its type is void (AnotherClass::*)()
. Notice that the class name is part of the type, so you can't simply store a pointer-to-member-function to an arbitrary class. Furthermore, to call a pointer-to-member-function, you need an instance pointer - you'd have to store that somehow, but those would have different types too!
What you could do instead in C++11 is use type-erasure:
std::function<void()> callback;
And assign an arbitrary callable to it:
template <typename F>
Button(F cb)
: callback(cb)
{ }
And then you could create a button using std::bind
:
Button* temp1 = new Button(std::bind(&OtherClass::LoadFile, this));
Button* temp2 = new Button(std::bind(&AnotherClass::SaveFile, this));
Now temp1->callback()
will actually call LoadFile()
on the instance of OtherClass
that it was constructed with. Which is what you wanted. And, we can still use free functions:
void whatever();
Button* temp3 = new Button(whatever);
Insert the usual caveats about using raw pointers and new
and preferring unique_ptr
.
You can't really have a pointer to a member function because it's meaningless w/o the hidden this
pointer on which the object is invoked.
There are a few common solutions to the problem you're trying to solve.
The C
way:
Store a void*
in addition to the function pointer. Then pass the void*
int the callback. This is less "safe", but is common in C.
OOP way #1:
Subclass Button
and have a virtual function on the base class, say onPress
that can be implemented in the subclasses.
OOP way #2:
Have a callback interface independent of Button
that your custom classes implement.
EDIT: Or use lambdas as mentioned in comments. I am still re-learning C++ the modern way myself.