2016-06-27 13 views
0

CRTPテンプレートのメンバポインタに問題があります。 このコードは、crtp派生クラスのメンバ関数ポインタを呼び出す仮想呼び出し関数です。派生クラスのメンバ関数ポインタ

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) ; 
} ; 

クラスGlfwDefaultKeyboardHandlerがKeyboardHandlerOptiとしてdrawKeyで初期化されます:: mDefaultCallback

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

とコールバックは

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) ; 
} 

と呼ばれている残念ながら、私はセグメンテーションフォルトを持っていると私はすることはできませんよ理由を理解する。私はデバッグで興味深い値を見つけました。 KeyboardHandlerOptiの構築時に、私が実際に理解していないことがあることがわかります。

defaultCallbackの値は0x4b7578で、デバッガは関数の名前を知ることができますが、mDefaultCallbackは "0x7ef360、この調整96"であり、両方のベクトルで同じ値です。

誰かが私に説明することができれば、どうして私はセグメンテーションを持つのですか?私はとても幸せになるでしょう。

答えて

4

メンバは、コンストラクタの初期化子リストに表示される順序で、ではなく、であるクラス定義にリストされている順番で初期化されます。 KeyboardHandlerOptiコンストラクタでは、mCallbackPressedmCallbackReleasedが最初に初期化され、次にmDefaultCallbackに値が割り当てられます。だからあなたは無駄なゴミでいっぱいにあなたのベクトルを詰める。正式には、プログラムは未定義の動作を示します。

は、それが

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

、ベクトルを移入するためにdefaultCallbackを使用してください。 mDefaultCallbackを最後まで移動することは技術的には必要ではなく、イニシャライザが実際に実行される順序と一致するだけです(イニシャライザが「間違った」順序になっているとコンパイラが警告すると思います)。

+0

本当にありがとうございます.GMMは警告を表示していませんでした。 –

関連する問題