C ++中的匿名内部类(Java样式的侦听器)

时间:2018-11-09 11:48:57

标签: c++ interface arduino listener anonymous-inner-class

我的C / C ++技能有点生锈,在过去的几年中,我主要从事Java工作。现在,我才开始玩Arduino,并做了一个简单的按钮类。我想添加一个事件监听器,所以我做了这样的事情:

class MyButton{
  public:
      MyButton(byte pin);
      bool isPressed();
      bool wasToggled();
      bool wasPressed();
      void eventLoop();
      inline void setListener(MyButtonListener* listener) { _listener = listener; }

  private:
      byte _pin;
      boolean _lastToggledState = false;
      MyButtonListener* _listener;
};



class MyButtonListener{
    public: 
        virtual void onPressed() = 0;

    private:
};

eventLoop()方法(旨在从Arduino loop()函数调用),在侦听器类中调用onPressed()方法:

void MyButton::eventLoop(){
    if( wasPressed() && _listener ){
        _listener->onPressed();
    }
}

到目前为止,一切还好。但是我不知道如何在Arduino主文件中实际分配和使用监听器。来自Java,我习惯做类似的事情

myBtn.setListener( new MyButtonListener(){
    void onPressed(){
        Serial.println("Pressed");
        toggleLed(); // toggleLed() is a method in the main Arduino file
    }
});

通过声明一个使用toggleLed()方法作为参数的新类,使它以非常复杂的方式工作(因为否则无法从新类内部访问它):

class BtnListener : public MyButtonListener{
    public:
        BtnListener(void* toggleFunction) : _toggleFunction(toggleFunction){ };

    private:
        void (*_toggleFunction)();

        void onPressed(){
            Serial.println("Pressed");
            _toggleFunction();
        };
};



myBtn.setListener( new BtnListener(toggleLed) );

在C ++中肯定有一种更便捷的方法来执行类似的操作吗?一个监听器是可行的(但是很丑)-我什至无法想象拥有10个按钮都需要不同监听器实现的恐怖...

2 个答案:

答案 0 :(得分:2)

在您的情况下,一种或最简单的方法是将侦听器存储为std::function<void()>,并且根本没有用于建模buttonlistener的实际类(如果您确实想封装它,但这不是必需的)。然后将lambda函数用于setListener调用,如下所示:

myBtn.setListener( [this]{
        Serial.println("Pressed");
        toggleLed(); // toggleLed() is a method in the main Arduino file
    });

答案 1 :(得分:2)

由于默认情况下Arduino IDE似乎未包含<functional.h>,因此我无法使用std::function<void()>使用答案。但是,经过一些试验,我意识到有一种更简单的方法,它还具有能够对侦听器进行建模的好处。

listener类仅包含指向每个侦听器回调函数的函数指针,以及一个为每个回调采用参数的构造函数。然后,只需创建一个新的侦听器类实例并将每个回调作为lambda传递,将非常方便。

class MyButton{
    public:
        inline void setListener(MyButtonListener* listener) { _listener = listener; }

    private:
        MyButtonListener* _listener;          
 }


class MyButtonListener{
    public:
        MyButtonListener(void* onPressed, void* onToggled) : onPressed(onPressed), onToggled(onToggled) {};
        void (*onPressed)();
        void (*onToggled)();
};



void MyButton::eventLoop(){
    if( _listener ){
        if( wasPressed() ){
            _listener->onPressed();
        }

        if( wasToggled() ){
            _listener->onToggled();
        }        
    }
}



myBtn.setListener( 
    new MyButtonListener( 
        // onPressed
        [](){
            Serial.println("Pressed");
            toggleLed();
        },
        // onToggled
        [](){
            Serial.println("Toggled");
        }            
    )
);

不确定此解决方案是否有任何缺点,但是它可以工作,可读且适合在Arduino上使用。