2015-02-06 14 views
5

Attualmente sto sperimentando con la libreria FLTK GUI ma non sono sicuro di cosa stia succedendo con le funzioni di callback —, in particolare il tipo casting è un po 'estraneo a me. L'esempio seguente mostra una finestra di base con un pulsante con l'etichetta "Press". Quando si preme il pulsante, l'etichetta cambia in "Fatto".Funzioni Casting/Callback

L'etichetta che viene passato alla funzione di callback viene dichiarata come tipo const char* e poi è gettato digitare void*, ma è possibile dichiarare questo come un std::string e poi gettato a void*? Preferisco utilizzare le stringhe C++ moderne della notazione char.

Inoltre, la sintassi è il modo migliore per trasmettere da un tipo all'altro? Ho visto prima il static_cast<type>(), ma qual è il modo più sicuro/migliore per fare un cast da const char* a void* o viceversa e perché? Cosa raccomanderebbe C++ 11?

#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(); 
} 
+0

ma è possibile dichiarare questo come uno std :: string e poi gettato a "void *"? Si. –

+1

@BartekBanachewicz Vuoi lanciare std :: string o un puntatore a std :: string? – harper

+0

Bene, un puntatore ad esso. –

risposta

6

(T)a fusione in stile, noto anche come fusione in stile C, è in realtà il peggior modo fare una conversione esplicita in C++. Questo perché è il più potente — convertirà felicemente quasi tutto, nascondendo facilmente errori gravi. È l'unica forma di conversione di tipo esplicita disponibile in C, ed è stata ereditata come tale da C++, ma non dovrebbe mai essere realmente utilizzata in codice C++ di qualità.

Il cast di word per void* è inutile — qualsiasi puntatore al tipo di oggetto può essere implicitamente convertito in un puntatore a void.

Il cast indietro a const char* nella richiamata è necessario, ma potrebbe essere eseguito con un static_cast<const char*>(userdata).

Per rispondere alla domanda su std::string: dipende dalla durata. È possibile convertire un std::string* in un void* e passarlo al callback. Lì, lo hai ricollocato su str::string* (e poi recuperi c_str() da esso per passare alla funzione label). Ma è necessario assicurarsi che il std::string puntato a sia ancora vivo (non è andato fuori ambito) per il momento in cui viene chiamato il callback. Se lo rendi una variabile locale in main, sei praticamente al sicuro.

Se lo si fa in questo modo, il codice sarà simile a questa:

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(); 
} 
+0

Mille grazie Angew - questo è esattamente il tipo di informazioni di cui avevo bisogno per aiutare a chiarire alcune cose nella mia testa e sono molto più felice di usare il codice che hai suggerito. Grazie per aver trovato il tempo di rispondere! –

+0

@EdwardJeckyll Se una risposta risolve il tuo problema, dovresti considerare di contrassegnarlo come tale * accettandolo * (facendo clic sul segno di spunta verde accanto ad esso, al massimo una risposta accettata per domanda). Questo contrassegna la domanda come risolta e fornisce sia al rispondente che a te una certa reputazione. È il [modo Overflow dello stack di dire "grazie, ha funzionato"] (http://stackoverflow.com/help/someone-answers). – Angew

+0

Capito, grazie Angew. –

0

Se il callback si aspetta un void* di quanto si può passare un puntatore a nulla. Ma il callback deve sapere come gestire l'argomento. Deve restituirlo a un tipo utilizzabile.

È possibile modificare la richiamata in modo che si aspetti un puntatore a std::string. Se si desidera avere un const char* nella richiamata si deve passare la stringa stile C al callback:

button->callback(xyz_callback, str.c_str()); 
+0

meno 1 - dire a qualcuno di usare 'c_str()' e non descrivere i problemi di gestione a vita, esp. in un callback. Lasciare il tuo codice nel codice della domanda precedente spezzerebbe le cose in modo orribile. – Yakk

+0

@Yakk Il callback è chiamato in modo sincrono. Il callback deve comunque ottenere la proprietà dei dati. Passare un puntatore a qualsiasi variabile locale ha lo stesso problema. Ma questo non fa parte della domanda. Non puoi aspettarti di leggere un libro di stile di programmazione qui. – harper

+0

buon punto: fanno un ':: run()' prima delle uscite di 'main'. – Yakk