2015-02-06 24 views
5

Obecnie eksperymentuję z biblioteką GUI FLTK, ale nie jestem do końca pewien, co się dzieje z funkcjami oddzwaniania. Specyfika oddzwaniania jest dla mnie nieco obca. Poniższy przykład pokazuje podstawowe okno z przyciskiem "Press". Po naciśnięciu przycisku etykieta zmieni się na "Gotowe".Funkcje odlewania/oddzwaniania

Etykieta, który jest przekazywany do funkcji wywołania zwrotnego jest zadeklarowany jako typ const char* a następnie odlewa się wpisywać void*, ale jest to możliwe, aby zadeklarować to jako std::string a następnie oddane do void*? Wolę używać nowoczesnych ciągów C++ niż notacja char.

Ponadto, czy składnia jest poniżej najlepszego sposobu przesyłania z jednego rodzaju do drugiego? Widziałem wcześniej używane static_cast<type>(), ale jaki jest najbezpieczniejszy/najlepszy sposób wykonania odlewania z const char* do void* i odwrotnie i dlaczego? Co poleciłby 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

ale jest to możliwe, aby zadeklarować to jako std :: string, a następnie oddane do "void *"? Tak. –

+1

@BartekBanachewicz Czy chcesz rzucić std :: string lub wskaźnik na std :: string? – harper

+0

Cóż, wskaźnik do niego. –

Odpowiedz

6

(T)a -Style odlewania, znany również jako odlew w stylu C, to rzeczywiście sposób najgorszy zrobić wyraźną konwersję w C++. Dzieje się tak dlatego, że jest to najpotężniejszy —, który z powodzeniem przekształci prawie wszystko, łatwo ukrywając poważne błędy. Jest to jedyna forma jawnej konwersji typu dostępnej w C, która została odziedziczona jako taka przez C++, ale nigdy nie powinna być używana w jakościowym kodzie C++.

Obsada word do void* jest niepotrzebna — dowolny wskaźnik do obiektu typu można niejawnie konwertowane do wskaźnika do void.

Oddanie z powrotem do const char* w oddzwonieniu jest konieczne, ale można to zrobić za pomocą static_cast<const char*>(userdata).

Aby odpowiedzieć na pytanie dotyczące std::string: zależy to od czasu życia. Możesz przekonwertować numer std::string* na void* i przekazać go do wywołania zwrotnego. Tam możesz odesłać go z powrotem do str::string* (a następnie pobrać z niego c_str(), aby przejść do funkcji label). Musisz jednak upewnić się, że wskazany std::string jest wciąż żywy (nie wykracza poza zakres) przed wywołaniem wywołania zwrotnego. Jeśli zmienisz ją na lokalną zmienną w main, jesteś prawie bezpieczny.

jeśli robisz to w ten sposób, kod będzie wyglądać następująco:

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

Wielkie dzięki Angew - to dokładnie ten rodzaj informacji, których potrzebowałem, aby pomóc w wyjaśnieniu niektórych rzeczy w mojej głowie i jestem o wiele szczęśliwszy, korzystając z kodu, który zasugerowałeś. Dziękuję za poświęcony czas na odpowiedź! –

+0

@EdwardJeckyll Jeśli odpowiedź rozwiąże problem, powinieneś rozważyć oznaczenie go przez * akceptując * (klikając zielony znacznik obok niego, najwyżej jedną akceptowaną odpowiedź na pytanie). Oznacza to, że pytanie zostało rozwiązane i daje zarówno odbierający, jak i pewną reputację. Jest to [sposób przepełnienia stosu "dziękuję, zadziałało"] (http://stackoverflow.com/help/someone-answers). – Angew

+0

Rozumiem, dziękuję Angew. –

0

Jeśli zwrotna oczekuje void* niż można przekazać wskaźnik do niczego. Ale callback musi wiedzieć, jak poradzić sobie z argumentem. Musi go przywrócić do użytecznego typu.

Możesz zmienić wywołanie zwrotne, aby oczekiwał wskaźnika na std::string. Jeśli chcesz mieć const char* w zwrotnego trzeba przejść ciąg C-stylu do callback:

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

minus 1 - mówienie komuś, żeby używało 'c_str()' i nie opisywanie problemów zarządzania na całe życie, zwł. w oddzwonieniu. Zrzucenie kodu do kodu powyższego pytania przerwałoby wszystko strasznie. – Yakk

+0

@Yakk Oddzwonienie nazywa się synchronicznie. Oddzwonienie musi mimo wszystko uzyskać własność danych. Przekazywanie wskaźnika do dowolnej zmiennej lokalnej ma ten sam problem. Ale to nie jest część pytania. Nie można się spodziewać czytania książki stylu programowania tutaj. – harper

+0

dobry punkt - wykonują ':: run()' zanim 'main' zakończy działanie. – Yakk