Passing I/O functions to a class.

I'm a first time c++ explorer having a hard time to figure out how to tell the compiler to do what I want...

For my arduino programs I use a kind of menu over serial line.

It might help to understand what I want to do to have a quick look at an example: a simple hardware menu interface over serial line as a kind of arduino software breadboard.

After cat&pasting the menu code too many times to too many sketches I decided to implement the menu functionality as a library to make reuse even easier. I had done similar things in other languages like c and FORTH but decided to take advantage of the situation and try out c++, not so sure any more if that was a good idea :wink:

I started coding on a Linux computer as I did not want to load all my early versions on an arduino. So I wrote and tested basic menu functionality on Linux. On an Arduino the menu would get input from one of it's hw interfaces like Serial and use the same (or another) interface for output. On the pc the I/O was on stdin/stdout.
So I experimented with passing function pointers to the Menu constructor or with defining menu I/O by #ifdef s.
I thought I could use that later to switch different Arduino interfaces, not being restricted to Serial.

I found different working approaches on Linux, but when I tried to use Serial I/O on the Arduino the compiler confused me a lot by not letting me do that and throwing me in a jungle of constructors/destructors, thinking that I want to redefine this-or-that. After a lot of reading, learning and trying different approaches I'm still not there yet.

Let me explain:

The menu takes input (if any) from one of the interfaces like serial, buffers it and returns immediately unless it just received an end token. So the menu must know how to test for input (nonblocking) and to read next byte. After an end token the menu interprets the input in a way defined by the user program and some internal stuff.

On the other hand the menu must have a way to inform the user about active keys, selected menu page, errors like unknown input, a missing number and the like.

So far so good, but now the arduino sketch defines it's menu pages, saying things like:
if on menu page "TEST" react on receiving menu token 'l' or 'r' by informing the user about the pwm value driving left/right motor and let him set a new value to test how much your two-wheel robot needs to start moving... and on pressing '!' store that values to the EEPROM...

So the sketch often wants to use the same I/O functions as the menu class does. This lead to all sorts of errors when trying that with Serial I/O and c++ (If I remember right I had an early c version that worked sort of...).

I thought I could do that along the lines

/* pseudo code */
Menu MENU(buffsize, submenus, &men_getchar [, other I/O function pointers]);

/* the sketch would then call MENU.out() family or use things like Serial.print() directly
    to define functionality of the menu pages */

Works well on linux, but not when I try to use it with Arduino Serial, one of the most common errors being that the compiler thinks I want to redefine Serial I/O functions. How do I tell that to the compiler and where would I put Serial.begin()?

I have tried a couple of other implementations, like to derive the Menu class from Serial which had the side effect of making me feel very stupid :wink:

I think the key point is that I want to be able to use all I/O interfaces (which might be coded as a class) in both the sketch and the menu class. Multiple menus on different I/O interfaces should also remain possible.

So before trying next dead end street let me ask:
What is the right approach to do that in c++?

I'm not fully grasping the problem here yet, but if you want to be able to use some interface within that class, can't you just have those interfaces as member variables of your class?

I'm assuming that the problem is that the base classes have function implementation by the same name. So, without changing the library functions, you need to access those classes via pointers, references or just instantiate the interface within your class. Just make sure it's initialized before using it. Typically the constructor would be short, and you would have an Init() function that must be called. You do not want exceptions thrown in either constructor or destructor, that's mostly the reason, I think.

Chaul:
I'm not fully grasping the problem here yet, but if you want to be able to use some interface within that class, can't you just have those interfaces as member variables of your class?

I had tried this with Serial but could not find out how to be able to use Serial from within the sketch and the class.
Also this does not look very flexible to me if I want to use another interface or use more then one in different menus.

Chaul:
I'm assuming that the problem is that the base classes have function implementation by the same name. So, without changing the library functions, you need to access those classes via pointers, references or just instantiate the interface within your class. Just make sure it's initialized before using it. Typically the constructor would be short, and you would have an Init() function that must be called.

Yes, I did come across naming conflicts.
Speaking about *.init functions I think one of my problems is that I don't know where to call Serial.init() from.

Another topic might be that I tried to pass a function pointer to an overloaded function. I don't even know if that is possible at all, but could not work it out with separate functions either...

I do not know how to access a class by a pointer, btw. What can you do with that?

Thanks for helping me :slight_smile:

OutOfLine:
So before trying next dead end street let me ask:
What is the right approach to do that in c++?

Pass it by reference. In all that post you didn't have much code. Post a minimal sketch that demonstrates what you are trying to do, even if it doesn't compile.

Something like this.

MyClass * pClass = new MyClass(var1, var2);
pClass->Init();

var1 and var2 are some variables, just to show that you can pass them into the constructor or Init(). However, I must warn you about using uninitialized pointer variables. You must set a value to the pointer. The example above would crash on the Init-call if the pointer was pointing to either 0 or some random place in memory.

A safer way would be to use reference like MyClass & rClass; but this requires that you pass the reference via the constructor. It would be too late in the Init() function.

The third way is to just instantiate it with MyClass oClass; but this means you can't pass any variables in the constructor and you'll have to set the Init variables separately or with the Init() function.

As for function pointers, I would rather use derived classes. Function pointers are used more in C, but in C++ it's kinda not necessary most of the time. There are object oriented principles that involve implementing a factory for the creation of different kinds of objects, but it would take a lot of time to get a hold of and on simple projects it would just overcomplicate things for what it's worth..

The Serial class is probably instantiated already somewhere. I haven't checked how that works. It looks like the begin() function is enough to initialize it. I haven't seen the need to derive from it, but it also looks like the LCD libraries for example do. I'm sorry I'm still a bit new to Arduino, but I'm not that new to object oriented programming.

Yes, or you can just pass the object via reference to a class function. The & marks reference. You have the class already instantiated and you just write the function definition like this:
Execute(MyClass & rClass);

Yes, only problem that I have tried too many approaches and they have all grown beyond 'minimal',
and need cleaning up (too much #ifdef magic and debugging code inside).

I have the code in git, so could start from any one of some quite different trial implementations.
But I'm not decided on what version to base discussion on.
That's why I ask for the right c++ approach first :wink:

Did I get that right, you suggest that I'd pass a reference to (let's say) Serial I/O functions from the sketch to the Menu constructor or some Menu.init() function? I would call Serial.init() from setup(), right?

Or did you mean to pass a reference to a class (let's say Serial)? I have never heard of pointers/references to a class before, btw.

Serial isn't a class. It's an instance of a class and you can pass a reference to it.

Example:

void displaySomething (HardwareSerial & whichPort)
  {
  whichPort.println ("Hello world.");  
  }

void setup ()
  {
  Serial.begin (115200);
  displaySomething (Serial);
  }  // end of setup

void loop () { }

Or even, to be fancier:

void displaySomething (Stream & whichPort)
  {
  whichPort.println ("Hello world.");  
  }

void setup ()
  {
  Serial.begin (115200);
  displaySomething (Serial);
  }  // end of setup

void loop () { }

And to use it in a class:

class myMenu 
  {
  private:
    Stream & port_; 
  public:
    myMenu (Stream & port) : port_ (port) { }
    void begin ();
  };

void myMenu::begin ()
  {
  port_.println ("Menu initialized."); 
  }

myMenu menu (Serial);

void setup ()
  {
  Serial.begin (115200);
  menu.begin ();
  }  // end of setup

void loop () { }

Thanks, that was one of my wrong assumptions, there must be some more.

Your code makes me smile: I once tried:

/*
 something.cpp  Passing a function pointer to a function to do something:
*/

#include <iostream>

bool something() {
  std::cout << "\t\"Something in the way she moves...\"\n";
  return true;
}

void do_it(bool (*do_something)(void)) {
  (*do_something)();
}


bool (*learned)(void);

void learn_anything(bool (*what)(void)) {
  learned=what;
}

void do_anything() {
  (*learned)();
}

int main() {
  std::cout << "something.cpp\n";

  std::cout << "\n  passing something as argument:\n";
  do_it(&something);

  std::cout << "\n  learning something:\n";
  learn_anything(&something);
  do_anything();

  std::cout << "\n(done)\n";
  return 99;	// test only ;)
}

Trying the same in a class was more difficult then I expected, though.

References have to be initialized in the constructor, as Chaul said, but it wasn't that bad.

Oh, thanks. This looks like a starting point.
I think I had tried a very similar example.

I must read up about streams, never really used them.
How do I call that for tests on a Linux text console (not Arduino)?

Hmm, but can I check a stream for input in a non blocking way?

Chaul:

MyClass * pClass = new MyClass(var1, var2);

pClass->Init();

Thanks, that was helpful.

Chaul:
A safer way would be to use reference like MyClass & rClass; but this requires that you pass the reference via the constructor. It would be too late in the Init() function.

I do not see a problem with that.

Chaul:
As for function pointers, I would rather use derived classes.

Like declaring Menu class based on serial class?
(Just learned that Serial is not the class, so maybe it is 'serial'?).

But what if the menu wants to read from Serial, but display informations somewhere else and then the errors on...?

@OutOfLine

Not sure where in this thread it fits, but on the Arduino I usually use the Streaming Library, like this:

#include <Streaming>
...
Serial << "Hello there " << ", i= " << i << endl;
...

And then when I compile for various reasons on another platform I use:

#include <iostream>
using namespace std;
ostream & Serial = cout;

... so now I can use throughout, the same

Serial << "Hello there " << ", i= " << i << endl;

Cheers,
John

@johncc:
Thank you for the nice hint, will try it later on.

OutOfLine:
Like declaring Menu class based on serial class?
(Just learned that Serial is not the class, so maybe it is 'serial'?).

But what if the menu wants to read from Serial, but display informations somewhere else and then the errors on...?

Serial port are instantiated from a class already, so it's not necessary to derive from them.

For example, from Arduino reference:
"All Arduino boards have at least one serial port (also known as a UART or USART): Serial."
"The Arduino Leonardo board uses Serial1 to communicate via RS232 on pins 0 (RX) and 1 (TX). Serial is reserved for USB CDC communication."

Anyways, if I'm reading this correctly, it looks like the instantiation is done in HardwareSerial.cpp/.h from a class named HardwareSerial into instances Serial, Serial1, and so on. This is included from Arduino.h so, at least you can trust that they are always accessible hardware supporting.. Since the Serial classes are already instantiated in memory, you should just pass the related instances by reference to save memory unless you insist on overriding some functions like read and write. Outside Arduino IDE this probably works in a different way.

However, my point about function pointers was that it kinda doesn't belong in C++ when you have other neater ways of doing the same thing in my opinion. Function pointers are typically used in C when you need to collect actions in an array and pass them into function calls. Nothing stops you from doing the same within a class though. It's a separate topic from above because I don't see what would the passed function be.