派生类上的成员函数指针

时间:2016-06-27 15:59:12

标签: c++11 crtp

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

使用drawKey将类GlfwDefaultKeyboardHandler初始化为KeyboardHandlerOpti :: mDefaultCallback

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

和Callback被调用

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,debuger可以告诉函数的名称,但mDefaultCallback是“0x7ef360,此调整为96”,两个向量中的值相同。

所以如果有人能向我解释为什么我会遇到段错误,我会非常高兴。

1 个答案:

答案 0 :(得分:4)

Memebers按照它们在类定义中列出的顺序进行初始化,按照它们出现在构造函数的初始化列表中的顺序进行初始化。在KeyboardHandlerOpti构造函数中,mCallbackPressedmCallbackReleased首先被初始化,然后才为mDefaultCallback分配一个值。所以你把你的载体装满了随机的垃圾。在形式上,您的程序表现出不确定的行为。

成功

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

即,使用defaultCallback填充向量。将mDefaultCallback移到最后并不是技术上必需的,它只是使列表中的顺序与初始化程序实际执行的顺序相匹配(我相信一些编译器会在初始化程序处于“错误”顺序时发出警告)。