Coding State Machine in C++ - c++

I'm attempting to code a state machine based on a gumball machine. I have a interface class of a basic state, while I have specific states that use this interface. I have four states, no_quarter, has_quarter, sold, and sold_out states. I also have a gumball machine class that handles these states and depending on which state my machine is in, it will go that class and do the needed action. Here is my code that is having the problem, I'll post my functions also.
Gumball_Machine.h
class Gumball_Machine
{
private:
int gumball_count;
State *current_state;
No_Quarter_State *nqs;
Has_Quarter_State *hqs;
Sold_State *ss;
Sold_Out_State *sos;
public:
Gumball_Machine(int inventory)
{
gumball_count = inventory;
nqs = new No_Quarter_State(this);
hqs = new Has_Quarter_State(this);
ss = new Sold_State(this);
sos = new Sold_Out_State(this);
if (gumball_count == 0)
set_state(sos);
else
set_state(nqs);
}
void insert_quarter()
{
current_state->insert_quarter();
}
void eject_quarter()
{
current_state->eject_quarter();
}
void turn_crank()
{
current_state->turn_crank();
}
void dispense()
{
current_state->dispense();
}
void set_state(State *new_state)
{
current_state = new_state;
}
State *get_no_quarter_state()
{
return nqs;
}
State *get_has_quarter_state()
{
return hqs;
}
State *get_sold_state()
{
return ss;
}
State *get_sold_out_state()
{
return sos;
}
No_Quarter_State.h
#ifndef NO_QUARTER_STATE_H_INCLUDED
#define NO_QUARTER_STATE_H_INCLUDED
#include "State.h"
class No_Quarter_State: public State
{
public:
No_Quarter_State(Gumball_Machine *gbm);
void insert_quarter();
void eject_quarter();
void turn_crank();
void dispense();
};
#endif // NO_QUARTER_STATE_H_INCLUDED
No_Quarter_State.cpp
#include "No_Quarter_State.h"
#include "Gumball_Machine.h"
No_Quarter_State::No_Quarter_State(Gumball_Machine *machine)
{
machine = machine;
}
void No_Quarter_State::insert_quarter()
{
cout << "You inserted a quarter.\n";
machine->set_state(machine->get_has_quarter_state());
}
void No_Quarter_State::eject_quarter()
{
cout << "You must insert a quarter before you can eject one.\n";
}
void No_Quarter_State::turn_crank()
{
cout << "You must insert a quarter before you can crank the handle.\n";
}
void No_Quarter_State::dispense()
{
cout << "You need to pay first before you can get a gumball.\n";
}
The line I'm having an issue is in the No_Quarter_State.cpp
machine->set_state(machine->get_has_quarter_state());
This is giving me a run-time error. I've seen examples like this but I'm not completely sure if this is legal in C++. I'm attempting to switch the state of my gumball machine object.
The error I get is a generic not responding error: "test.ext has stopped working". I'm using CodeBlocks to code this.

In the constructor, the presumed member variable machine is hidden by the parameter.
No_Quarter_State::No_Quarter_State(Gumball_Machine *machine)
{
machine = machine;
}
You can fix this by using initializer list syntax instead:Thanks Sneftel and NathanOliver
No_Quarter_State::No_Quarter_State(Gumball_Machine *machine)
: machine(machine)
{
}
However, in regular method functions, you would have to use this-> if you named the method parameter the same as the member variable. A typical style used to avoid that issue is to prepend m_ or append _ to member names.

Related

log4cplus does not show all messages

We are building a module that is part of a full embedded Linux operating systems. We are using log4cplus for diagnostics.
log.properties contains:
log4cplus.logger.CompanyGlue=TRACE, console
cm_bind_helper.h contains much more complicated than this. All of the DBG_XXX messages appear on the console.
#include "qobject.h"
#include "log4cplus/dbglog.h"
class bind_helper : public QObject
{
protected:
const char *debugModuleName = "CompanyGlue";
log4cplus::Logger debugModule { Logger::getInstance(debugModuleName) };
bool set_value(CMPath path, PType &input)
{
auto old_value = CMRoot()->getValue(path);
if (input != old_value) {
DBG_DEBUG("Changing " << path << " to " << input);
}
}
}
cm_bridge.cpp contains much more code than this. However, none of the DBG_XXX messages appear on the console.
#include "cm_bridge.h"
#include "cm_bind_helpers.h"
struct CompanyContentModelBridge::detail_ : public bind_helper
{
std::shared_ptr<company::device_base> base;
detail_(QObject *parent)
: bind_helper(parent)
{
configure_system_advanced_control();
}
void configure_system_advanced_control();
std::string get_exported_file_size();
}
using detail_ = CompanyContentModelBridge::detail_;
void detail_::configure_system_advanced_control()
{
base->add_get_only_entry<std::string>("SPDSZ", get_exported_file_size());
}
std::string detail_::get_exported_file_size()
{
DBG_INFO("get exported file size");
//diag("exported file size");
}
I have tried various ways to configure log4cplus in cm_bridge.cpp, including the same two lines in cm_bind_helpers.h and as follows. I also removed them assuming that inheritance would handle it. Nothing made the DBG_XXX messages appear.
DBG_IMPL_DEBUG_MODULE(CompanyGlue);
Eventually, I added this function to cm_bind_helpers.h. It worked when called from its own class but failed when called from get_exported_file_size() (with comment removed).
void diag(std::string_view what) {
DBG_DEBUG("bind helper diag " << what);
}
I'm stumped. I do not know why messages are being suppressed from one file but not the other.

C++ Difficulty Creating Instance of Class within Singleton Class

I have a fairly good template (as in snippet of code) I pull out whenever I need a singleton class. I am now trying to apply it within my project to allow me to control a single instance of a web server. I can make a web server without encasing it in my class. When I try to encase it within the class I'm apparently too unskilled to pull it off.
I've tried the obvious Googling and searching here. I've read relevant posts. I am sure this does not mean I have a unique problem, just that I've not figured out the right way to fix it. Here's what I am working with:
webserver.h:
#include <ESP8266WebServer.h>
#include <FS.h>
class WebServer {
private:
// Singleton Declarations
static bool instanceFlag;
static WebServer *single;
WebServer() {}
// Other Declarations
FS *filesystem;
ESP8266WebServer server();
String getContentType(String);
bool handleFileRead(String);
public:
// Singleton Declarations
static WebServer* getInstance();
~WebServer() {instanceFlag = false;}
// Other Declarations
void initialize(int);
void handleLoop();
};
webserver.cpp:
#include "webserver.h"
bool WebServer::instanceFlag = false;
WebServer* WebServer::single = NULL;
WebServer* WebServer::getInstance() {
if(!instanceFlag) {
single = new WebServer();
instanceFlag = true;
return single;
} else {
return single;
}
}
void WebServer::initialize (int port) {
ESP8266WebServer server(port);
FS *filesystem;
filesystem->begin();
Serial.print("Open: http://");
Serial.print(WiFi.hostname().c_str());
Serial.println(".local");
server.onNotFound([]() {
if (!single->handleFileRead(single->server.uri())) {
single->server.send(404, "text/plain", "404: File not found.");
}
});
server.begin();
Serial.print("HTTP server started on port ");
Serial.print(port);
Serial.println(".");
}
String WebServer::getContentType(String filename) {
if (single->server.hasArg("download")) {
return "application/octet-stream";
} else if (filename.endsWith(".htm")) {
return "text/html";
} else if (filename.endsWith(".html")) {
return "text/html";
} else if (filename.endsWith(".css")) {
return "text/css";
} else if (filename.endsWith(".js")) {
return "application/javascript";
} else if (filename.endsWith(".png")) {
return "image/png";
} else if (filename.endsWith(".gif")) {
return "image/gif";
} else if (filename.endsWith(".jpg")) {
return "image/jpeg";
} else if (filename.endsWith(".ico")) {
return "image/x-icon";
} else if (filename.endsWith(".xml")) {
return "text/xml";
} else if (filename.endsWith(".pdf")) {
return "application/x-pdf";
} else if (filename.endsWith(".zip")) {
return "application/x-zip";
} else if (filename.endsWith(".gz")) {
return "application/x-gzip";
} else {
return "text/plain";
}
}
bool WebServer::handleFileRead(String path) {
Serial.println("handleFileRead: " + path);
if (path.endsWith("/")) {
path += "index.htm";
}
String contentType = getContentType(path);
String pathWithGz = path + ".gz";
if (filesystem->exists(pathWithGz) || filesystem->exists(path)) {
if (filesystem->exists(pathWithGz)) {
path += ".gz";
}
File file = filesystem->open(path, "r");
single->server.streamFile(file, contentType);
file.close();
return true;
}
return false;
}
void WebServer::handleLoop() {
single->server.handleClient();
}
The errors I am getting are all similar to the following:
src\webserver.cpp: In member function 'bool WebServer::handleFileRead(String)':
src\webserver.cpp:81:23: error: 'WebServer::single->WebServer::server' does not have class type
single->server.streamFile(file, contentType);
I get the idea of "does not have a class type", I just have no idea what it means here. In my mind, "single" is a pointer to the class so I'm unclear what that reference is not working.
Obviously, there are ample examples out there how to do a web server without encapsulating it. Other things I need to do for this project lend itself to creating that requirement.
There are some mistake in your code.
In webserver.h:
...
private:
// Singleton Declarations
static bool instanceFlag;
static WebServer *single;
WebServer() {}
// Other Declarations
FS *filesystem;
ESP8266WebServer *server; // <--- remove the parentheses and make it a pointer
String getContentType(String);
bool handleFileRead(String);
...
In webserver.cpp:
In WebServer::initialize I am guessing you want to initialize the class server and filesystem not locals, so it should probably look like this:
void WebServer::initialize (int port) {
server = new ESP8266WebServer(port);
filesystem = new FS();
...
}
And now everywhere you use the server you have to use the -> operator.
For example:
void WebServer::handleLoop() {
single->server->handleClient();
}
Please keep in mind that server and filesystem objects have to be deleted to avoid memory leaks.
EDIT:
You get the new error because FS has no constructor without arguments.
FS's constructor looks like this: FS(FSImplPtr impl) : _impl(impl) { }, here you can see that FSImplPtr is a typedef for std::shared_ptr<FileImpl>, so you need to provide this as a parameter.
It works your way, because SPIFFS's existence is declared here and is of type FS.
If you want to use SPIFFS, you have to use it like this: filesystem = &SPIFFS;, not like you mentioned in the comments (FS* filesystem = &SPIFFS;) because your way creates a new temporary variable named filesystem, and probably you expect to initiate the filesystem in the class, not a local one.

C++ member of class updated outside class

I have a question about pointers and references in C++. I am a programmer who normally programs in C# and PHP.
I have two classes (for now) which are the following.
The X/Y in Controller are continuously changing but i want them up to date in the Commands. I have multiple commands like Forward, Turn, Backward etc.
When i make the commands i give them the controller but the state (X, Y) of the controller are updating every second.
How can i fix that the controller attribute in the Commands are getting updated also every second?
class Forward : ICommand
{
Controller ctrl;
void Execute() {
int CurrentX = ctrl.X;
int CurrentY = ctrl.Y;
//Check here for the current location and calculate where he has to go.
}
}
class Controller
{
int X;
int Y;
void ExecuteCommand(ICommand command) {
command.Execute();
}
}
Main.cpp
Controller controller;
Forward cmd1 = new Forward(1, controller);
Turn cmd2 = new Turn(90, controller);
Forward cmd3 = new Forward(2, controller);
controller.Execute(cmd1);
controller.Execute(cmd2);
controller.Execute(cmd3);
I have read something about pointers and references and i think i have to use this but don't know how to use it in this situation.
(code can have some syntax errors but that's because i typed over. Everything is working further except for the updating).
If you use references rather than copy objects you can see changes.
#include <iostream>
using namespace std;
class ICommand
{
public:
virtual ~ICommand() = default;
virtual void Execute() = 0;
};
class Controller
{
public:
int X = 0;
int Y = 0;
void ExecuteCommand(ICommand & command) {
// ^-------
command.Execute();
}
};//,--- semicolons required
class Forward : public ICommand //note public
{
const int step;
Controller ctrlCopy;
Controller & ctrlReference;
public:
Forward(int step, Controller & ctrl) :
step(step),
ctrlCopy(ctrl), //this is a copy of an object
ctrlReference(ctrl) //this is a reference to an object
{
}
void Execute() {
std::cout << "copy: " << ctrlCopy.X << ", " << ctrlCopy.Y << '\n';
std::cout << " ref: " << ctrlReference.X << ", " << ctrlReference.Y << '\n';
//Check here for the current location and calculate where he has to go.
ctrlCopy.X += 10;
ctrlReference.X += 10;
}
};//<--- semicolons required
int main() {
Controller controller;
Forward cmd1(1, controller);
//Turn cmd2(90, controller); //Left for the OP to do
Forward cmd3(2, controller);
controller.ExecuteCommand(cmd1);
//controller.ExecuteCommand(cmd2);
controller.ExecuteCommand(cmd3);
//Do it again to show the copy and reference difference
std::cout << "Once more, with feeling\n";
controller.ExecuteCommand(cmd1);
controller.ExecuteCommand(cmd3);
}
Giving
copy: 0, 0
ref: 0, 0
copy: 0, 0 // [1]
ref: 10, 0 // [2]
Once more, with feeling
copy: 10, 0
ref: 20, 0
copy: 10, 0
ref: 30, 0
1 shows that the copy has X and Y of 0, while the reference shown in [2] has moved by the stated step (in controller.ExecuteCommand(cmd3))
Note, we don't need to use new to make this work (don't forget delete if you use new).
Also, void ExecuteCommand(ICommand command) now takes a reference instead otherwise the by-value copy does "slicing" (e.g. see here)

How to call a class within a function definition in c++

Its my first time asking for help on programming. I have been working on a register program for my programming class for weeks which involves classes. Its rather frustrating for me. I have to use two classes: StoreItem and Register. StoreItem deals with the small list of items that the store sells. The register class deals mostly with processing the items, making a total bill and asking the user to pay with cash.
Here is the StoreItem.cpp file:
//function definition
#include <string>
#include <iostream>
#include "StoreItem.h"
#include "Register.h"
using namespace std;
StoreItem::StoreItem(string , double)
{
//sets the price of the current item
MSRP;
}
void StoreItem::SetDiscount(double)
{
// sets the discount percentage
MSRP * Discount;
}
double StoreItem::GetPrice()
{ // return the price including discounts
return Discount * MSRP;
}
double StoreItem::GetMSRP()
{
//returns the msrp
return MSRP;
}
string StoreItem::GetItemName()
{
//returns item name
return ItemName;
}
StoreItem::~StoreItem()
{
//deletes storeitem when done
}
Here is the Register.cpp:
Note that the last 5 function definitions in this one arent finished yet...
// definition of the register header
#include "Register.h"
#include "StoreItem.h"
using namespace std;
Register::Register()
{ // sets the initial cash in register to 400
CashInRegister = 400;
}
Register::Register(double)
{ //accepts initial specific amount
CashInRegister ;
}
void Register::NewTransAction()
{ //sets up the register for a new customer transaction (1 per checkout)
int NewTransactionCounter = 0;
NewTransactionCounter++;
}
void Register::ScanItem(StoreItem)
{ // adds item to current transaction
StoreItem.GetPrice();
// this probably isnt correct....
}
double Register::RegisterBalance()
{
// returns the current amount in the register
}
double Register::GetTransActionTotal()
{
// returns total of current transaction
}
double Register::AcceptCash(double)
{
// accepts case from customer for transaction. returns change
}
void Register::PrintReciept()
{
// Prints all the items in the transaction and price when finsished
}
Register::~Register()
{
// deletes register
}
My main question is where Register::ScanItem(StoreItem)... is there a way to correctly call a function from the storeItem Class into the Register scanitem function?
You have:
void Register::ScanItem(StoreItem)
{ // adds item to current transaction
StoreItem.GetPrice();
// this probably isnt correct....
}
This means that the ScanItem function takes one argument of type StoreItem. In C++ you can specify just the type and make the compiler happy. But if you intend to use the argument, you must give it a name. For example:
void Register::ScanItem(StoreItem item)
{
std::cout << item.GetItemName() << " costs " << item.GetPrice() << std::endl;
}
To be able to call a member function of the object you're passing as the parameter, you need to name the parameter, not just its type.
I suspect you want something like
void Register::ScanItem(StoreItem item)
{
total += item.GetPrice();
}

How to handle and avoid Recursions

I'm using custom classes to manage a vending machine. I can't figure out why it keeps throwing a stack overflow error. There are two versions to my program, the first is a basic test to see whether the classes etc work, by pre-defining certain variables. The second version is what it should be like, where the variables in question can change each time the program is ran (depending on user input).
If anyone can suggest ways of avoiding this recursion, or stack overflow, I'd great. Below is the code for the three classes involved;
class Filling
{
protected:
vector<Filling*> selection;
string fillingChosen;
public:
virtual float cost()
{
return 0;
}
virtual ~Filling(void)
{
//needs to be virtual in order to ensure Condiment destructor is called via Beverage pointer
}
};
class CondimentDecorator : public Filling
{
public:
Filling* filling;
void addToPancake(Filling* customerFilling)
{
filling = customerFilling;
}
~CondimentDecorator(void)
{
delete filling;
}
};
class Frosted : public CondimentDecorator
{
float cost()
{ //ERROR IS HERE//
return (.3 + filling->cost());
}
};
Below is the code used to call the above 'cost' function;
void displayCost(Filling* selectedFilling)
{
cout << selectedFilling->cost() << endl;
}
Below is part of the code that initiates it all (main method);
Filling* currentPancake = NULL;
bool invalid = true;
do
{
int selection = makeSelectionScreen(money, currentStock, thisState);
invalid = false;
if (selection == 1)
{
currentPancake = new ChocolateFilling;
}
else if...
.
.
.
.
else
invalid = true;
} while (invalid);
bool makingSelection = true;
CondimentDecorator* currentCondiment = NULL;
do
{
int coatingSelection = makeCoatingSelectionScreen(money, currentStock, thisState);
if (coatingSelection == 1)
currentCondiment = new Frosted;
else if (coatingSelection == 2)...
.
.
.
else if (coatingSelection == 0)
makingSelection = false;
currentCondiment = thisSelection;
currentCondiment->addToPancake(currentPancake);
currentPancake = currentCondiment;
displayCost(currentPancake);
//Below is the code that DOES work, however it is merely meant to be a test. The
//above code is what is needed to work, however keeps causing stack overflows
//and I'm uncertain as to why one version works fine and the other doesn't
/*currentCondiment = new Frosted;
currentCondiment->addToPancake(currentPancake);
currentPancake = currentCondiment;
displayCost(currentPancake);
currentCondiment = new Wildlicious;
currentCondiment->addToPancake(currentPancake);
currentPancake = currentCondiment;
displayCost(currentPancake);*/
} while (makingSelection);
displayCost(currentPancake);
delete currentPancake;
The infinite recursion happens when you call displayCostwith a Frosted whose filling is a Frosted as well. And that happens right here:
currentCondiment->addToPancake(currentPancake);
currentPancake = currentCondiment;
displayCost(currentPancake);
You set the filling of currentCondiment to currentPancake, then call displayCost with currentCondiment.
In the process you also leak the memory that was originally assigned to currentPancake.
Btw currentCondiment = thisSelection; also leaks memory.
Idea: Use smart pointers like std::unique_ptr to get rid of the leaks.