派生 class 上的成员函数指针

Member function pointer on derived class

我在使用 CRTP 模板中的成员指针时遇到一些问题。 这里的代码是一个虚调用函数,调用一个crtp派生的成员函数指针class.

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

class GlfwDefaultKeyboardHandler 使用 drawKey 初始化为 KeyboardHandlerOpti::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”,它在两个向量中是相同的值。

所以如果有人能向我解释为什么我有段错误我会很高兴。

成员按照它们在 class 定义中列出的顺序进行初始化,而不是 按照它们在构造函数的初始化列表中出现的顺序进行初始化。在KeyboardHandlerOpti构造函数中,mCallbackPressedmCallbackReleased先被初始化,然后才给mDefaultCallback赋值。所以你把你的向量塞满了随机垃圾。正式地,您的程序表现出未定义的行为。

成功

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

也就是说,使用 defaultCallback 来填充向量。将 mDefaultCallback 移动到末尾在技术上不是必需的,它只是使列表中的顺序与实际执行初始化程序的顺序相匹配(我相信一些编译器会在初始化程序处于 "wrong" 顺序时发出警告)。