Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type Casting / Callback Functions

Tags:

c++

I am currently experimenting with the FLTK GUI library but am not really sure what is going on with callback functions—specifically the type casting stuff is a bit foreign to me. The example below shows a basic window with a button labeled "Press". When you press the button the label changes to "Done".

The label that is passed to the callback function is declared as type const char* and then it is cast to type void*, but is it possible to declare this as a std::string and then cast to void*? I prefer to use modern C++ strings than char notation.

Also, is the syntax below the best way of casting from one type to another? I have seen static_cast<type>() used before but what is the safest/best way to do a cast from const char* to void* or vice versa and why? What would C++11 recommend?

#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Native_File_Chooser.H>
#include <string>

void xyz_callback(Fl_Widget* w, void* userdata)
{

  Fl_Button* b = (Fl_Button*)w; //cast widget w to button and assign to b

  b->label((const char*)userdata);  //cast userdata back to type const char*
}


int main(int argc, char **argv)
{
  Fl_Window *window = new Fl_Window(340,180);
  Fl_Button *button = new Fl_Button(20,40,300,100, "label");
  button->label("Press");
  button->labelfont(FL_BOLD+FL_ITALIC);
  button->labelsize(36);
  button->labeltype(FL_SHADOW_LABEL);
  button->when(FL_WHEN_RELEASE);

  const char* word = "Done";
  button->callback(xyz_callback, (void*)word); //cast word to type void*

  window->end();
  window->show(argc, argv);
  return Fl::run();
}
like image 864
Edward Jeckyll Avatar asked Feb 06 '15 15:02

Edward Jeckyll


1 Answers

(T)a-style casting, also known as C-style casting, it actually the worst way to do an explicit conversion in C++. That's because it's the most powerful—it will happily convert almost anything, easily hiding grave errors. It's the only form of explicit type conversion available in C, and it was inherited as such by C++, but should never really be used in quality C++ code.

The cast of word to void* is unnecessary—any pointer to object type can be implicitly converted to a pointer to void.

The cast back to const char* in the callback is necessary, but could be done with a static_cast<const char*>(userdata).

To address the question about std::string: that depends on lifetime. You can convert a std::string* to a void* and pass it to the callback. In there, you'd cast it back to str::string* (and then retrieve c_str() from it to pass to the label function). But you must make sure that the std::string pointed to is still alive (hasn't gone out of scope) by the time the callback is called. If you make it a local variable in main, you're pretty much safe.

If you do it that way, the code will look like this:

void xyz_callback(Fl_Widget* w, void* userdata)
{
  Fl_Button* b = static_cast<Fl_Button*>(w);

  b->label(static_cast<std::string*>(userdata)->c_str());
}


int main(int argc, char **argv)
{
  Fl_Window *window = new Fl_Window(340,180);
  Fl_Button *button = new Fl_Button(20,40,300,100, "label");
  button->label("Press");
  button->labelfont(FL_BOLD+FL_ITALIC);
  button->labelsize(36);
  button->labeltype(FL_SHADOW_LABEL);
  button->when(FL_WHEN_RELEASE);

  std::string word = "Done";
  button->callback(xyz_callback, &word);

  window->end();
  window->show(argc, argv);
  return Fl::run();
}
like image 111
Angew is no longer proud of SO Avatar answered Oct 05 '22 21:10

Angew is no longer proud of SO