How to setup a non-static callback to an object's member function?

Hi,

I’m writing a wrapper around the Arduino Keypad Library. First I created all the new functionality on a normal Sketch which uses the Keypad lib.
Then I modified the sketch to convert it to a library by creating a class.
So far everything is fine except that in the new library I can’t get the callback from the Keypad Lib to compile.
The compiler complains “error: invalid use of non-static member function” in the line where the callback function is set up.

I have looked around the internet, looking into other Arduino libraries’s source code but I can’t find a solution or clear example on how to do this.

All that I need is a way to get the callback work for a member function that is not static but a member of another ‘object’.

I’ll really appreciate any help.

Here is a minimal code where the issue is replicate as it happens in my project:

MyClass.h

#ifndef MYCLASS_H
#define MYCLASS_H

class MyClass {
 public:
   void addEventListener(void (*listener));
 
 private:
   void (*eventListener);
};

#endif

I named MiddleClass the class that uses the MyClass library.
MyClass.cpp

#include"MyClass.h"

MyClass::MyClass() {}

void MyClass::addEventListener(void (*listener)){
 eventListener = listener;
}

MiddleClass.cpp

#ifndef MIDDLECLASS_H
#define MIDDLECLASS_H

#include "MyClass.h"

class MiddleClass {
 public: 
         MyClass myClass;  
         void setItUp();  
 private:
         void middleClassCallBackHandler();
};
#endif

MiddleClass.cpp

#include "MiddleClass.h"

void MiddleClass::setItUp() {
 myClass.addEventListener(MiddleClass::middleClassCallBackHandler);
}

void MiddleClass::middleClassCallBackHandler() { }

This is the main Sketch.

// Sketch ----------------


#include "MiddleClass.h"

MiddleClass middleClass;

void setup() {
 middle.setItUp();
}

void loop() { }

missing ()

void MyClass::addEventListener(void (*listener) ())
void (*eventListener) ();

Hi,
Thanks for your answer.
Yes, you were right, I did miss the function parenthesis () but I still getting the same compile error.
I have change the names of the classes to ‘A’ and ‘B’ and shorter the member functions names so that the program looks more clean. I will re post the code and include an .ino for download.
Thanks again.

#include "A.h"

A a;

void setup() {
  a.setItUp();
}

void loop() { }

The A class header:

#ifndef A_H
#define A_H

#include "B.h"

class A {
  public: 
      B b;  
      void setItUp();  
  private:
      void callBackHandler();
};
#endif

The A class cpp:

#include "A.h"

void A::setItUp() {
  b.addEventListener(A::callBackHandler); // -> ERROR: "invalid use of non-static member function"
}

void A::callBackHandler() { }

The B class:

#ifndef B_H
#define B_H

class B {
  public:
    void addEventListener(void(*listener)());
  
  private:
    void (*eventListener)();
    void somethingHappened();
};
#endif

The B class cpp:

#include"B.h"

void B::addEventListener(void(*listener)()) {
  eventListener = listener;
}

void somethingHappened() {
  // Notify listener objec at it's delegate (callback) member function.
  eventListener();
}

SimpreCallbackFromClass2.zip (2.02 KB)

Short Answer:
You can’t.

Longer Answer:
You can “sort of" do it using a Lambda function as demonstrated here: https://forum.arduino.cc/index.php?topic=506401.msg3453517#msg3453517. But, besides being ugly, I don’t think you can do it from within a class method (void A::setItUp() in your example).

Better Answer:
Since you’re defining the interface, create a CallBack class that contains a callBack() method. Then, pass a pointer to an object of this class rather than a pointer to the callback function. Check this: https://forum.arduino.cc/index.php?topic=524167.msg3831858#msg3831858

Thank you very much.
I will read your links.

I have change the names of the classes to 'A' and 'B' and shorter the member functions names so that the program looks more clean.

The code does NOT look "more clean". Good looking code uses names that make sense. A and B as class names mean NOTHING.

THINK about what you are trying to do. You have an interrupt being generated, which is equivalent to a doorbell ringing. You have some undefined number of instances of the class A, equivalent to people in the house. You want ONE of them to deal with the interrupt when it happens, without defining which one. That's like expecting ONE of the people in the house, but not ALL of them, to deal with the doorbell ringing. How can you possibly expect that to work?

A much better approach would be to write your own version of the keypad library that doesn’t use callbacks.
Reading a keypad is not rocket science, you just need two nested for-loops and a 2D array to keep the previous states.

Pieter