C++ 中的匿名内部 class(Java 式侦听器)
Anonymous inner class in C++ (Java-style listener)
我的C/C++技能有点生疏,过去几年我大部分时间都在Java工作。现在我刚开始玩Arduino,做了一个简单的按钮class。我想添加一个事件监听器,所以我做了这样的事情:
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()
方法 class:
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
}
});
我让它以一种非常复杂的方式工作,通过声明一个新的 class 将 toggleLed()
方法作为参数(因为它不能从新的 class 否则):
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 个按钮都需要不同的听众实现的恐怖...
在您的情况下,一种或最简单的方法是将侦听器存储为 std::function<void()>
并且根本没有实际的 class 来为按钮侦听器建模(您仍然可以如果你真的想封装它,但这不是必需的)。然后使用 lambda 函数调用 setListener,如下所示:
myBtn.setListener( [this]{
Serial.println("Pressed");
toggleLed(); // toggleLed() is a method in the main Arduino file
});
由于默认情况下 Arduino IDE 似乎不包含 <functional.h>
,因此我无法使用 std::function<void()>
使用答案。然而,经过一些试验后,我意识到有一种更简单的方法,它还具有能够为听者建模的好处。
侦听器 class 仅包含指向每个侦听器回调函数的函数指针,以及一个为每个回调获取参数的构造函数。然后创建一个新的侦听器实例非常方便 class 并将每个回调作为 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 上使用。
我的C/C++技能有点生疏,过去几年我大部分时间都在Java工作。现在我刚开始玩Arduino,做了一个简单的按钮class。我想添加一个事件监听器,所以我做了这样的事情:
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()
方法 class:
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
}
});
我让它以一种非常复杂的方式工作,通过声明一个新的 class 将 toggleLed()
方法作为参数(因为它不能从新的 class 否则):
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 个按钮都需要不同的听众实现的恐怖...
在您的情况下,一种或最简单的方法是将侦听器存储为 std::function<void()>
并且根本没有实际的 class 来为按钮侦听器建模(您仍然可以如果你真的想封装它,但这不是必需的)。然后使用 lambda 函数调用 setListener,如下所示:
myBtn.setListener( [this]{
Serial.println("Pressed");
toggleLed(); // toggleLed() is a method in the main Arduino file
});
由于默认情况下 Arduino IDE 似乎不包含 <functional.h>
,因此我无法使用 std::function<void()>
使用答案。然而,经过一些试验后,我意识到有一种更简单的方法,它还具有能够为听者建模的好处。
侦听器 class 仅包含指向每个侦听器回调函数的函数指针,以及一个为每个回调获取参数的构造函数。然后创建一个新的侦听器实例非常方便 class 并将每个回调作为 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 上使用。