Im relatively new to C++. I'm applying the State design pattern for an IoT application that simply polls a sensor every 15 secs, then if its still connected online, send the data somewhere, and if its not, then save it to an array. However I've been at this code for a few days now and I'm stuck at a part where when I added a TransitionTo in OfflineState I get errors. From my understanding it is because TransitionTo(new OnlineState), OnlineState is declared after I try to use the function, however if I change the order of declaration I'll get an error in TransitionTo(new OfflineState). Coming from C, I expected to just do something similar to adding a prototype, in this case I tried Forward declaring the states classes, but it didn't work. I would like to understand why is it wrong OOP-wise and how to fix it.
#include <iostream>
#include <typeinfo>
#include <WiFi.h>
#include <WiFiClientSecure.h>
// The base State class declares methods that all Concrete State should
// implement and also provides a backreference to the Context object, associated
// with the State. This backreference can be used by States to transition the
// Context to another State.
const char *ssid = "XXX";
const char *password = "XXX";
unsigned long lastTime = 0;
const unsigned long timerDelay = 15000;
int flag = 0;
const TickType_t connectionDelay = 1500 / portTICK_PERIOD_MS;
WiFiClientSecure client;
class State
{
// @var Context
protected:
Context * context_;
public:
virtual ~ State ()
{
}
void set_context (Context * context)
{
this->context_ = context;
}
virtual void Connect () = 0;
virtual void CheckConnection () = 0;
virtual void setMyAttribute (float x) = 0;
};
// The Context defines the interface of interest to clients. It also maintains a
// reference to an instance of a State subclass, which represents the current
// state of the Context.
class Context
{
// @var State A reference to the current state of the Context.
private:
State * state_;
public:
float sensorData = 0;
Context (State * state):state_ (nullptr)
{
this->TransitionTo (state);
}
~Context ()
{
delete state_;
}
// The Context allows changing the State object at runtime.
void TransitionTo (State * state)
{
Serial.println ("Transitioning");
if (this->state_ != nullptr)
delete this->state_;
this->state_ = state;
this->state_->set_context (this);
}
// The Context delegates part of its behavior to the current State object.
void Connect ()
{
this->state_->Connect ();
}
void CheckConnection ()
{
this->state_->CheckConnection ();
}
void setMyAttribute (float x)
{
this->state_->setMyAttribute (x);
}
};
// Concrete States implement various behaviors, associated with a state of the Context
class OfflineState:public State
{
public:
virtual void Connect () override
{
Serial.println ("connect from offlineState called");
WiFi.begin (ssid, password);
Serial.print ("Connecting to wifi...");
for (int i = 0; i < 10; i++)
{
if (WiFi.status () != WL_CONNECTED)
{
Serial.print ('.');
vTaskDelay (connectionDelay);
}
else
{
i = 10;
Serial.println ();
Serial.println ("Connected !");
this->context_->TransitionTo (new OnlineState);
}
}
}
void CheckConnection () override
{
Serial.println ("Check connection from offlinestate called");
}
void setMyAttribute (float x) override
{
CheckConnection ();
}
};
class OnlineState:public State
{
public:
void Connect () override
{
Serial.println ("Already connected");
}
void CheckConnection () override
{
Serial.println ("Check connection from onlineState called");
if (WiFi.status () != WL_CONNECTED)
{
Serial.println ("Disconnected!");
this->context_->TransitionTo (new OfflineState);
}
}
void setMyAttribute (float x) override
{
CheckConnection ();
}
};
Context *context = new Context (new OfflineState);
void
setup ()
{
WiFi.mode (WIFI_STA);
lastTime = millis ();
Serial.begin (115200);
context->Connect ();
context->CheckConnection ();
}
void
loop ()
{
if (millis () > (lastTime + timerDelay))
{
context->CheckConnection ();
lastTime = millis ();
}
}
I've tried making Connect() virtual void so it's declared after both states.
void OnlineState::Connect() {
{
std::cout << "OnlineState: Already connected.\n";
}
}
But I still get errors since in the class declaration, the class appears to be abstract.
Aucun commentaire:
Enregistrer un commentaire