Using virtual methods with Arduino - c++

I have a small piece of Arduino code that gives me compilation error:
error: no matching function for call to 'PushButton::PushButton(int, LeftButtonEvent*)
In its own header file I have two classes:
class Event
{
public:
virtual void handle() {
}
};
class PushButton
{
public:
PushButton(int pinButton, Event *event);
uint8_t read();
private:
uint8_t _buttonState;
Event _event;
};
And the source file for classes:
PushButton::PushButton(int pinButton, Event *event)
{
// implementation
}
uint8_t PushButton::read() {
// implementation
return _buttonState;
}
In the main ino sketch header file I have defined a new class that extends Event class:
class LeftButtonEvent : public Event {
public:
virtual void handle();
};
And in the sketch source file I provide the implementation for the handle method and use it:
void LeftButtonEvent::handle() {
log("Is working!!!!!");
}
LeftButtonEvent leftButtonEvent;
PushButton leftButton;
void setup() {
leftButton = PushButton(PIN_LEFT_BUTTON, &leftButtonEvent);
}
I was expecting the constructor for PushButton to accept a LeftButtonEvent type because it extends Event class, but it looks like it doesn't like it.
Am I missing something?

As there is only incomplete code and I couldn't test it directly, there is example how it's possible to get it work (it's all in one sketch, Arduino IDE 1.6.12, C++11):
class Event {
public:
virtual void handle() = 0;
};
class EventLeft : public Event {
public:
virtual void handle() {
Serial.println("EventLeft");
}
} leftEvent;
class EventRight : public Event {
public:
virtual void handle() {
Serial.println("EventRight");
}
} rightEvent;
class PushButton {
public:
PushButton(int8_t _pin, Event * _event) : pin(_pin), state(true), event(_event) {
pinMode(pin, INPUT_PULLUP);
}
void check() {
if (! digitalRead(pin)) { // inverted logic
if (state) event->handle();
state = false;
} else {
state = true;
}
}
private:
int8_t pin;
bool state;
Event * event;
};
PushButton buttons[] = {
{4, &leftEvent},
{5, &rightEvent}
};
void setup() {
Serial.begin(115200);
}
void loop() {
delay(10);
for (PushButton & button : buttons) button.check();
//// if the range based for loop above doesn't work, you have to use old school one:
// for (uint8_t i = 0; i < 2; ++i) buttons[i].check();
}

Related

How to find type of pointer

I have a optional property event that I define as a pointer in this struct:
struct AnimatedSprite {
//...some other properties
Event *event;
};
Let's say I want to store a StartTransitionEvent , defined like this:
class Event {
public:
Event() = default;
};
class StartTransitionEvent: public Event {
public:
int test = 1;
};
I can create and assign the StartTransitionEvent:
auto sprite = AnimatedSprite{};
auto newEvent = StartTransitionEvent{};
sprite.event = &newEvent;
But how do I get the type once I need to call something like:
eventBus->EmitEvent<StartTransitionEvent>(sprite->event);
Should I do some sort of checking on my event pointer to get to the StartTransitionEvent? Or maybe not use pointers at all and go for a std::variant to store the event with all it's possible child-classes?
You could use double dispatch, a.k.a. visitor pattern and let the specific Event visit the EventBus.
So something like
class Event
{
public:
virtual void Emit(EventBus& eventBus) = 0;
};
class StartTransitionEvent : public Event
{
public:
void Emit(EventBus& eventBus) override
{
eventBus.EmitEvent(this);
}
};
sprite.event.Emit(eventBus);
Assuming you're designing such a hierarchy, your EventBus class should be able to work with the base Event class. You achieve that through virtual functions in the Event class:
struct Event {
Event() = default;
virtual ~Event() = default;
virtual void action1(); // event-specific actions
virtual void action2();
virtual void action3();
};
struct StartTransitionEvent : Event {
void action3() override; // override some actions
};
struct EventBus {
void emit(Event& event) {
// ...
event.action1();
// ...
event.action2();
// ...
event.action3();
}
};
int main() {
StartTransitionEvent event;
EventBus bus;
bus.emit(event);
}

C++ Observer Mode, "does not name a type" compile error

I am writing an Arduino program where LEDs and a bunch of other electronics are controlled by different buttons. To simplify the code, I am using the Observer Mode:
class Observer observes EventThrowers, who performs check() every frame and notifies Observers if necessary. The code definition for Observer and EventThrower looks like this:
class Observer {
public:
virtual void handleEvent(int label, bool state) = 0; // Virtual method called by EventThrowers.
};
class EventThrower {
private:
std::vector<Observer *> observer_list;
protected:
void notifyObservers(int label, bool state) {
for (Observer *observer : observer_list) {
observer->handleEvent(label, state);
}
}
public:
virtual void check() = 0; // Virtual method used in loop() for frame checking.
void addObserver(Observer *_observer) {
this->observer_list.push_back(_observer);
}
};
And my LEDCtrl class (an Observer) and ButtonClick class (an EventThrower) definitions are:
class LEDCtrl : public Observer {
public:
// properties
LEDCtrl(int _led_pin) { ... } // constructor
void handleEvent(int label, bool state) { ... } // overridden handleEvent method
private:
void toggleLight(bool new_status) { ... } // assistant method
};
class ButtonClick : public EventThrower {
public:
// properties
ButtonClick(int _button_pin, int _default, int _label) { ... } // constructor
void check() { ... } // overridden check() that is called every frame to check the status of the button and choose to notify Observers or not
};
My initialization of a LEDCtrl-ButtonClick instance pair looks like:
ButtonClick *buttonClick1 = new ButtonClick(BUTTON1, 0, 0);
LEDCtrl *ledCtrl1 = new LEDCtrl(LED1);
buttonClick1->addObserver(ledCtrl1);
However, the above code throws this compile error:
error: 'buttonClick1' does not name a type
buttonClick1->addObserver(ledCtrl1);
^~~~~~~~~~~~
How can I fix this?

How to pass pointer to a member within class to outer class?

I am trying to pass a pointer to memeber of class(Dialog::handler) from its method(in scope of Dialog::render) to some outer method(Button::OnClick).
Here is a small example:
class Button
{
public:
void OnClick(void (*handler)())
{
handler();
}
};
class Dialog
{
public:
void handler()
{
//do stuff
}
void render()
{
auto button = new Button;
//Source of problem
button->OnClick(this->*handler);
}
};
But compiler shows error:
non-standard syntax; use '&' to create a pointer to member
Also I triend other combinations, like:
this->handler.
&this.handler.
this.*handler.
etc
But obviously they failed.
You could use std::function and pass it a lambda in which you've caught this of the object you'd like to call back:
#include <functional>
#include <iostream>
class Button {
public:
void OnClick(std::function<void()> handler) {
handler();
}
};
class Dialog {
public:
void handler() {
std::cout << "Dialog::handler\n";
}
void render() {
auto button = new Button;
// a lambda catching "this" Dialog.
button->OnClick([this] { this->handler(); });
delete button; // you didn't delete your button
}
};
int main() {
Dialog d;
d.render();
}
But it looks like you should probably inherit from a common base class that has a virtual void handler() so you can pass object pointers/references around instead. A rough idea:
#include <iostream>
class VisualBase {
public:
virtual void handler() = 0;
virtual ~VisualBase() = 0;
};
VisualBase::~VisualBase() {}
class Button : public VisualBase {
public:
void handler() override {}
void OnClick(VisualBase* caller) {
caller->handler();
}
};
class Dialog : public VisualBase {
public:
void handler() override {
std::cout << "Dialog::handler\n";
}
void render() {
Button button;
button.OnClick(this);
}
};
int main() {
Dialog d;
d.render();
}

A list with the same type as the class it's contained within

I'm trying to create a simple events system, which will have many different events. So, I've tried to create an event class which allows you to register functions, taking the correct type of event, and returning a boolean.
What I want is that the method post in any subclass of Event will take that subclass rather than Event, and the functions in the list listeners in each subclass should take the correct subclass type. Here's the code I already have, which forces the function to cast to the correct event type:
events.h:
namespace events {
class Event {
public:
static const std::List<bool (*)(Event)> listeners;
void post(Event event);
}
class ExampleEvent : Event {
int eventData;
}
}
events.cpp:
namespace events {
void Event::post(Event event) {
for(int i = 0; i < listeners.size(); i++) {
if(listeners[i](event)) return;
}
}
}
Is there some way I can get this to work with subclassed events without having to do the following?
bool handleExample(Event event) {
ExampleEvent exampleEvent = (ExampleEvent)event;
std::cout << exampleEvent.eventData << std::endl;
return false;
}
// Somewhere else in the code
ExampleEvent::listeners.push_back(&handleExample);
I apologise for any incorrect code, I don't quite have the rules of the language perfect yet.
The common way is to use CRTP:
namespace events {
template<typename Derived>
class Event {
public:
static const std::list<bool (*)(Derived)> listeners;
void post(Derived event)
{
static_cast<Derived&>(*this).post(event);
}
};
class ExampleEvent : Event<ExampleEvent> {
int eventData;
void post(ExampleEvent event)
{
//implement post
}
};
}
Just use virtual functions:
namespace events {
class EventHandler {
public:
static const std::list<Event*> listeners;
void post() {
for (Event * listener : listeners) {
if (listener->post()) break;
}
}
};
class BaseEvent {
public:
virtual bool post() = 0;
virtual ~BaseEvent() {}
};
class ExampleEvent : public BaseEvent { // use public inheritance
int eventData;
public:
virtual bool post() override {
if (eventData == 0) return true;
return false;
}
};
}

class has no constructor forward declaration

I'm trying to create a state engine in my game for the different screens. id start screen, maybe a file chooser in the future, overworld map, menu screen, etc. But when I forward declare the class it says there are no constructors.
GameState.h:
#pragma once
class GameState
{
public:
virtual ~GameState() {}
virtual void Update() {}
virtual void HandleEvents() {}
virtual void Draw(Graphics& gfx) {}
GameState* getCurrentState()
{
return currentState;
}
void ChangeState(GameState* state)
{
currentState = state;
}
protected:
SDL_Renderer* renderer;
GameState* currentState;
};
GameStates.h
#pragma once
#include "GameState.h"
#include "Texture.h"
#include "Keyboard.h"
class TitleGameState;
class IntroGameState : public GameState
{
public:
IntroGameState(SDL_Renderer* renderer, KeyboardClient& kbd)
:
kbd(kbd)
{
background = new Texture("red.png", renderer);
this->renderer = renderer;
}
~IntroGameState() {}
void HandleEvents()
{
while (!kbd.KeyEmpty())
{
KeyEvent e = kbd.ReadKey();
switch (e.GetCode())
{
case SDLK_RETURN:
if (e.IsPress())
{
currentState = new TitleGameState(renderer, kbd);
}
break;
}
}
}
void Logic() {}
void Draw(Graphics& gfx)
{
background->Draw(0, 0, gfx);
}
private:
Texture* background;
KeyboardClient& kbd;
};
class TitleGameState : public GameState
{
public:
TitleGameState(SDL_Renderer* renderer, KeyboardClient& kbd)
:
kbd(kbd)
{
background = new Texture("blue.png", renderer);
}
~TitleGameState() {}
void HandleEvents()
{
while (!kbd.KeyEmpty())
{
KeyEvent e = kbd.ReadKey();
switch (e.GetCode())
{
case SDLK_RETURN:
if (e.IsPress())
{
printf("OK");
}
break;
}
}
}
void Logic() {}
void Draw(Graphics&gfx)
{
background->Draw(0, 0, gfx);
}
private:
Texture* background;
KeyboardClient& kbd;
};
I define the class right afterwards, and I know I can just move it above IntroGameState, however when I implement the menu game state, it will go back and forth between the menu state and the overworld state. How can I get around this?
Compiler Error:
error C2514: 'TitleGameState' : class has no constructors
File: gamestates.h
Line: 28
Line 28 is this line of code:
currentState = new TitleGameState(renderer, kbd);
The error on the line currentState = new TitleGameState(renderer, kbd); is because the compiler has yet to see the constructor for the class. It doesn't know how to compile this code.
If you forward declare the class class TitleGameState; all you can declare is pretty much a pointer TitleGameState*.
To compile the code you have, you need to define the class before using. Note: defining the class does not mean defining all the methods as well. A class definition consists of the method and member declarations.
class TitleGameState : public GameState
{
public:
TitleGameState(SDL_Renderer*, KeyboardClient&);
~TitleGameState();
void HandleEvents();
// ...
};
class IntroGameState : public GameState
{
// ...
}
After the definition of the classes, you can then define the member functions;
/*inline*/ void TitleGameState::HandleEvents()
// inline is needed if the method is defined in a header file
// to help avoid linker errors
{
// ...
}