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();
}
(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();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With