gone
gone

Reputation: 1129

C++ passing pointer to child's function back to parent class

[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

Answers (2)

Sean
Sean

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

Josh Kelley
Josh Kelley

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

Related Questions