1

I am new to C++ & I need to call functions of one class from another class. And so that the classes do not know anything about each other. How to do it in Arduino environment?

class Encoder {
  using CallBack2 = void( * )(const int, const int);
  using CallBack0 = void( * )();
  private:
    CallBack2 callbackUpDown;
    CallBack0 callbackTab;
    CallBack0 callbackLongPress;
  public:
    Encoder() {}

void Setup(CallBack2 updown, CallBack0 tab, CallBack0 cbLongPress) { callbackUpDown = updown; callbackTab = tab; callbackLongPress = cbLongPress; }

void Loop() { if (true) { callbackUpDown(-1, 300); callbackTab(); callbackLongPress(); } } };

class Menu { public: void UpDown(const int direction, const int count) {} void Tab() {} };

class RTC { public: void Setup() {} void Toggle() {} };

class Display { public: void Toggle() {} };

Encoder encoder = Encoder(); RTC rtc = RTC(); Menu menu = Menu(); Display display = Display();

void setup() { rtc.Setup(); encoder.Setup(menu.UpDown, menu.Tab, []{display.Toggle();rtc.Toggle();}); }

void loop() { encoder.Loop(); }

Output:

In file included from sun.ino:47:0:
callback.h: In function 'void setup()':
callback.h:52:75: error: invalid use of non-static member function 'void Menu::UpDown(int, int)'
   encoder.Setup(menu.UpDown, menu.Tab, []{display.Toggle(); rtc.Toggle();});
                                                                           ^
callback.h:28:7: note: declared here
  void UpDown(const int direction, const int count) {}
       ^~~~~~

Thank you!

Andre
  • 27
  • 6

2 Answers2

1

What you are doing here

encoder.Setup(menu.UpDown, menu.Tab, []{display.Toggle();rtc.Toggle();});

is not only passing a function pointer. You are passing a member function pointer. This is 2 levels more difficult than function pointers on their own.

  1. The syntax of declaring a member function pointer is different. You need to include the class name in the function pointer declaration. It would look like

    using CallBack2 = void( Menu::* )(const int, const int);
    
  2. When calling a member function pointer, you need an object to call the function on.

Unfortunately, this is so hard that I can't turn your code into a working example. If you want to be able to read your code in 3 months or if you want others to be able to read your code, stick to normal function pointers. They are hard enough.

Suggestion: implement free functions that do what you want:

void menuUpDown(const int dir, const int count)
{
  menu.UpDown(dir, count);
}
void menuTab()
{
  menu.Tab();
}

void setup() { rtc.Setup(); encoder.Setup(menuUpDown, menuTab, []{display.Toggle();rtc.Toggle();}); }

Or, since you're already using lambdas (are you aware of that?), you can also

void setup() {
  rtc.Setup();
  encoder.Setup(
    [](const int dir, const int count){menu.UpDown(dir, count);}, 
    []{menu.Tab();},
    []{display.Toggle();rtc.Toggle();}
  );
}

Note that pupils and students might not have been introduced to the concept of lambdas. If you publish such code online, people might not be able to change it themselves because they don't understand it.

Thomas Weller
  • 1,058
  • 1
  • 8
  • 22
0

Also, Using Static Methods Or Non-Member Functions (C-Style)

class MyClass {
  public:
    static void onMsg(int num1, int num2) {
      // NOTE: Can't call any non-static method functions here!
    }
};

class LibraryClass { using CallBack = void( * )(int, int); private: CallBack callBack; public: void Setup(CallBack callBackFunc) { callBack = callBackFunc; } void Loop() { callBack(1, 2); } };

MyClass myClass; LibraryClass libraryClass;

void setup() { libraryClass.Setup(&myClass.onMsg); // Provide the instance and function to call }

void loop() { libraryClass.Loop(); }

Andre
  • 27
  • 6