2016-06-27 10 views
0

Ich habe einige Probleme mit einem Mitglied Zeiger in einer CRTP-Vorlage. Hier ist der Code eine virtuelle Aufruffunktion, die einen Mitgliedsfunktionszeiger auf eine von crtp abgeleitete Klasse aufruft.Mitglied Funktionszeiger auf abgeleitete Klasse

class KeyboardHandler { 
public: 
    virtual void keyPressed(KeyboardKey) = 0; 
    virtual void keyReleased(KeyboardKey) = 0; 
    KeyboardHandler & operator=(const KeyboardHandler &) = default ; 
}; 

template<class T> 
class KeyboardHandlerOpti : public KeyboardHandler { 
public: 

    using KeyboardCallback = void (T::*)(KeyboardKey key, KeyboardStatus status) ; 

KeyboardHandlerOpti(KeyboardCallback defaultCallback); 

virtual void keyPressed(KeyboardKey key) override final; 
virtual void keyReleased(KeyboardKey key) override final ; 


std::vector<KeyboardCallback> mCallbackPressed ; 
std::vector<KeyboardCallback> mCallbackReleased ; 

KeyboardHandlerOpti & operator=(const KeyboardHandlerOpti &) = default ; 

private: 
    KeyboardCallback mDefaultCallback ; 
}; 


class GlfwDefaultKeyboardHandler : 
     public KeyboardHandlerOpti<GlfwDefaultKeyboardHandler> { 
public: 
    GlfwDefaultKeyboardHandler() ; 

    GlfwDefaultKeyboardHandler & operator=(const GlfwDefaultKeyboardHandler &) = default ; 

private: 
    //This is type of KeyboardCallback 
    void drawKey(KeyboardKey key, KeyboardStatus status) ; 
} ; 

Die Klasse GlfwDefaultKeyboardHandler mit drawKey als KeyboardHandlerOpti :: mDefaultCallback

template<class T> 
KeyboardHandlerOpti<T>::KeyboardHandlerOpti(KeyboardCallback defaultCallback) : 
    mDefaultCallback(defaultCallback), 
    mCallbackPressed(getKeyboardKeyCount(), mDefaultCallback), 
    mCallbackReleased(getKeyboardKeyCount(), mDefaultCallback) { 
} 

und Rückruf sind aufgerufen, mit

template<class T> 
void KeyboardHandlerOpti<T>::keyPressed(KeyboardKey key) { 
    KeyboardCallback c = mCallbackPressed[getKeyValue(key)] ; 
    (dynamic_cast<T *>(this)->*c)(key, KeyboardStatus::ePressed) ; 
    //(this->*c)(key, KeyboardStatus::ePressed) ; 
} 

Leider habe ich einen segfault initialisiert wird, und ich bin nicht in der Lage verstehen warum. Ich habe im Debug einen interessanten Wert gefunden. Ich kann bei der Konstruktion von KeyboardHandlerOpti sehen, dass ich Dinge habe, die ich nicht wirklich verstehe.

defaultCallback Wert ist 0x4b7578 und Debuger kann den Namen der Funktion, aber mDefaultCallback ist "0x7ef360, diese Anpassung 96" und es ist der gleiche Wert in beiden Vektoren.

Also wenn mir jemand erklären kann warum ich den segfault habe wäre ich sehr glücklich.

Antwort

4

Mitglieder werden in der Reihenfolge initialisiert, in der sie in der Klassendefinition nicht in der Reihenfolge aufgeführt sind, in der sie in der Initialisierungsliste im Konstruktor angezeigt werden. In KeyboardHandlerOpti Konstruktor, mCallbackPressed und werden zuerst initialisiert, und erst dann wird mDefaultCallback ein Wert zugewiesen. Also stopfst du deine Vektoren voller Zufallsmüll. Formal weist Ihr Programm undefiniertes Verhalten auf.

Machen Sie es

template<class T> 
KeyboardHandlerOpti<T>::KeyboardHandlerOpti(KeyboardCallback defaultCallback) : 
    mCallbackPressed(getKeyboardKeyCount(), defaultCallback), 
    mCallbackReleased(getKeyboardKeyCount(), defaultCallback), 
    mDefaultCallback(defaultCallback) 
{ 
} 

Das heißt, verwenden defaultCallback die Vektoren zu füllen. Das Verschieben von mDefaultCallback zum Ende ist technisch nicht notwendig, es bewirkt nur, dass die Reihenfolge in der Liste mit der Reihenfolge übereinstimmt, in der Initialisierer tatsächlich ausgeführt werden (ich glaube, einige Compiler warnen, wenn Initialisierer in der "falschen" Reihenfolge sind).

+0

Vielen Dank Ich habe die Warnung nicht gesehen, weil Glm so viele Warnungen generieren, weil ich -pedantische .... –