Reputation: 1129
[Ubuntu, C++11, g++]
I'm having difficulty understanding how to pass a pointer to a child class function back to the parent class.
Since all my use cases require a signal handler to terminate the program, I've decided to implement the necessary parts of it in my abstract class and allow a hook for custom processing.
So, I would like the child classes to be able to pass a pointer to their own version of the "stop" function into the 'setupSIG_Handler' method. The 'setupSIG_Handler' then assigns this pointer to the global variable void (*stopFunction)() which is called from the Signal Handler itself.
There will only ever be one instance of the child.
Below is my code (only showing the relevant sections), and I'm getting syntax errors from the compiler in the setupSIG_Handler signature and the call to it from the Derived class' constructor.
Would anyone be able to help me understand how to make this work?
Cheers,
Nap
Abstract.h
class Abstract {
protected:
void setupSIG_Handler(void (*myStopFunction)()) <= ERROR
public:
virtual void stop() = 0;
}
Abstract.cpp
void (*stopFunction)();
static void sigSIGINThandler(int sigNum, siginfo_t *siginfo, void *context) {
std::cerr << std::endl << "Shutting Down Robot" << std::endl;
(*stopFunction)();
exit(0);
}
void NXT::setupSIG_Handler(void (*myStopFunction)()) { <= ERROR
stopFunction = myStopFunction;
struct sigaction ourSIGINTrecord, oldSIGINTrecord;
ourSIGINTrecord.sa_sigaction = &sigSIGINThandler;
sigaction(SIGINT, &ourSIGINTrecord, NULL);
}
Derived.h
class Derived : Abstract {
public:
virtual void stop();
}
Derived.cpp
Derived::Derived() {
setupSIG_Handler(&Derived::stop); <= ERROR
}
void Derived::stop(){
setMotors(0);
}
EDIT @Sean & @Josh: Thanks for explaining so quickly. Yes, I understood the difference between a static and instantiated method, just not familiar with how to handle it in C++.
Upvotes: 0
Views: 1021
Reputation: 62472
You're trying to pass a pointer to a member function into a method that just takes a pointer to a C-style function, and this will cause you problems.
Think of it this way, when you attempt to call the derived stop
method how will the sigSIGINThandler
function know which instance to call stop
against..?
To get around this use the std::function class to represent the callback:
#include <functional>
std::function<void(void)> stopFunction;
static void sigSIGINThandler(int sigNum, siginfo_t *siginfo, void *context)
{
std::cerr << std::endl << "Shutting Down Robot" << std::endl;
stopFunction();
exit(0);
}
void NXT::setupSIG_Handler(std::function<void(void)> myStopFunction)
{
stopFunction = myStopFunction;
struct sigaction ourSIGINTrecord, oldSIGINTrecord;
ourSIGINTrecord.sa_sigaction = &sigSIGINThandler;
sigaction(SIGINT, &ourSIGINTrecord, NULL);
}
Now you can register your handler like this (using a lambda):
Derived::Derived()
{
auto handler=[this]{stop();};
setupSIG_Handler(handler);
}
Alternatively you can use bind
.
Upvotes: 3
Reputation: 58352
setupSIG_Handler
takes a pointer to a function, but Derived::Derived
tries to pass a pointer to a (non-static) member function. A pointer to a function is not the same type as a pointer to a member function, because (non-static) member functions take an implicit this
parameter.
See the C++ FAQ.
Upvotes: 2