I am trying to implement an Observer/Subject design pattern between multiple classes. My compiler keeps returning to me the following:
[Done] exited with code=3221225477 in 0.603 seconds.
I assumed this was a success, until I realized nothing worked. I found out (through commenting and uncommenting code) that the crash occurs in 2 places, either when I try to attach an Observer to a child class of Subject, or when I try to call the notify method (which in turn updates the observer). Furthermore, as you will see, the LogObserver default constructor (Child class of Observer), should create and open a file called "gamelog.txt", but fails to do even that. I am not receiving any specific error message, so I dont know why it is crashing or where it is going wrong. Any and all help debugging this?
I'll show the code for the relevant .h and cpp files here, what I expected was for a file to be created, for the observer to be attached to OrderList (child class of Subject), and finally for the text file to be written to upon adding and order to orderlist (which should trigger the Notify method).
Here is the main driver:
#include "LoggingObserver.h"
#include "Orders.h"
void testLoggingObserver(){
//3 main issues
//1: File is NOT created upon logObserver default constructor
//2: The Attach method seems to crash the program
//3: Keep receiving error for "unidentified reference" to methods
//create instances of classes
LogObserver* logObserver;
OrdersList * orderList;
//CRASHES HERE
//Add the observer to the subjects
orderList->Attach(logObserver);
//CRASHES HERE
orderList->addOrder(new DeployOrder());
}
int main(){
testLoggingObserver();
cout<<"LogObserver Default Here!"<<endl;
return 0;
}
Here is the Header for LoggingObserver:
#pragma once
#include <iostream>
#include <vector>
#include <fstream>
#include <set>
#include <algorithm>
#include <list>
#include <iterator>
#include <string>
using namespace std;
//An Interface ILoggable. This interface will be inherited by all classes that can be the subject
//of the logging mechanism
#ifndef I_LOGGABLE_HPP
#define I_LOGGABLE_HPP
class ILoggable{
public:
//virtual ~ILoggable();
//Will create and return a string to be output to the log file
virtual string stringToLog()=0;
};
#endif
//#ifndef SUBJECT
//#define SUBJECT
class Observer;
//Subject Class will have a list of Observers and methods to add/remove and notify observers
class Subject{
private:
//list of Observers
list<Observer*> *observers;
public:
//default contructor and destructor
//Subject();
//~Subject();
//Methods to add, remove, and notify Observers
virtual void Attach(Observer* o)=0;
virtual void Detach(Observer* o)=0;
virtual void Notify()=0;
//friend classes
friend class GameEngine;
friend class OrdersList;
friend class Order;
friend class Command;
friend class CommandProcessor;
};
//#endif
//#ifndef OBSERVER
//#define OBSERVER
//Observer Class will have a method to update the state of the observer
class Observer{
private:
public:
//destructor
~Observer();
//method to update state of observer
virtual void Update(Subject* subject) = 0;
protected:
//default constructor
//Observer();
};
//#endif
//#ifndef LOG_OBSERVER
//#define LOG_OBSERVER
class GameEngine;
//This class will override the update method to write the state of the subject to the log file
class LogObserver: public Observer{
private:
//file to write to
ofstream logFile;
//variables attributed to phase
string playerName;
string phaseName;
//GameEngine* subjectGameEngine;
//variables attributed to game statistics
int totalContinents;
bool winnerStatus;
string conqueredContinent;
public:
LogObserver();
//LogObserver(GameEngine* aSubjectEngine);
~LogObserver();
//update method
void Update(Subject* subject) override;
//To display player information and current pahse information
void logToGameLog(const string& logEntry);
};
//#endif
Here is the .cpp for LoggingObserver:
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <list>
#include <algorithm>
#include "LoggingObserver.h"
using std::vector;
using std::list;
//Below we will implement all the abstract functions we declared in the previous LogginObserver.h Header File
//========================================ILoggable Class======================================
//Default constructor
//========================================Subject Class======================================
//Default constructor
/*
Subject::Subject(){
observers = new list<Observer*>;
}
//destructor
Subject::~Subject(){
delete observers;
}
*/
/*
//Implementation of Add method (adds an observer to the observers list)
void Subject::Attach(Observer* o){
observers->push_back(o);
}
//Implementation of Remove method (removes an observer from the observers list)
void Subject::Detach(Observer* o){
observers->remove(o);
}
//Implementation of the Notify method (will call on the observers update method)
void Subject::Notify(){
list<Observer*>::iterator i = observers->begin();
for(;i != observers->end(); ++i){
//using "this" to pass the subject to the update method
(*i)->Update(this);
}
}
*/
//========================================Observer Class======================================
//Default constructor
Observer::~Observer(){
}
//========================================LogObserver Class======================================
//Default constructor (will open file)
LogObserver::LogObserver(){
logFile.open("gamelog.txt", ios::app);
cout<<"LogObserver Default Here!"<<endl;
}
//Destructor
LogObserver::~LogObserver(){
logFile.close();
}
//Overriding the update method from Observer (will grab relevant information and update file)
void LogObserver::Update(Subject* subject){
ILoggable* loggable = dynamic_cast<ILoggable*>(subject);
if(loggable){
string logEntry = loggable -> stringToLog();
logToGameLog(logEntry);
}
}
//implementing loToGameLog function (will write to file)
void LogObserver::logToGameLog(const string& logEntry){
logFile << logEntry << endl;
}
Here is the .h for Orders:
#pragma once
#include <vector>
#include <string>
#include <iostream>
#include "LoggingObserver.h"
class Order : public ILoggable
{
public:
// default constructor
Order();
// constructor with order type
Order(std::string orderType);
// copy constructor
Order(Order &o);
// Overload the << operator to describe the order
friend std::ostream & operator << (std::ostream& os, Order& order);
// checks if an order is valid
bool validate();
// executes an order
void execute();
bool getIsExecuted();
void setIsExecuted(bool isExecuted);
std::string getOrderType();
void setOrderType(std::string orderType);
// override the assignment operator
Order& operator=(Order& o);
//Overriden stringToLog() method fromILoggable
string stringToLog() override;
private:
std::string orderType;
bool isExecuted;
};
// specific order classes:
class DeployOrder : public Order
{
public:
// default constructor
DeployOrder();
};
class AdvanceOrder :public Order
{
public:
// default constructor
AdvanceOrder();
};
class BombOrder : public Order
{
public:
// default constructor
BombOrder();
};
class BlockadeOrder : public Order
{
public:
// default constructor
BlockadeOrder();
};
class AirliftOrder : public Order
{
public:
// default constructor
AirliftOrder();
};
class NegotiateOrder : public Order
{
public:
// default constructor
NegotiateOrder();
};
class OrdersList : public Subject
{
private:
std::vector<Order *> orders;
public:
// default constructor
OrdersList();
// copy constructor
OrdersList(OrdersList &ol);
// destructor
~OrdersList();
std::vector<Order *> getOrders();
Order* createOrder(std::string orderType);
// add an order to the list
void addOrder(Order *order);
// change the position of an order in the order list
void move(int listPosition1, int targerList);
// remove an order from the order list
void remove(int listPosition);
// prints all the orders in the list
void printOrdersList();
// Overload the << operator to describe the order list
friend std::ostream& operator<<(std::ostream& os, OrdersList& ordersList);
// override the assignment operator
OrdersList& operator=(OrdersList& ol);
void Attach(Observer* o) override;
void Detach(Observer* o) override;
void Notify() override;
};
inline void testOrdersLists()
{
using namespace std;
// create an order list and add every type of oder to it
OrdersList * ol = new OrdersList();
ol->createOrder("Deploy");
ol->createOrder("Advance");
ol->createOrder("Bomb");
ol->createOrder("Blockade");
ol->createOrder("Airlift");
ol->createOrder("Negotiate");
// print all the elements in the order list
cout << "\nInitial Order List:\n" << endl;
cout << *ol;
// 'execute' an order
cout << "\n";
ol->getOrders().front()->execute();
// remove an order
cout << "\n";
ol->remove(2);
// print all the elements in the new order list
cout << "\nRemoved Order 2 from list:\n" << endl;
cout << *ol;
// move an order
cout << "\n";
ol->move(1,2);
// print all the elements in the new order list
cout << "\nChanged the first order to be the seconds order:\n" << endl;
cout << *ol;
}
And here is the .cpp for orders:
#include <iostream>
#include <vector>
#include <string>
#include "Orders.h"
#include "LoggingObserver.h"
// list<Order *> orders = ol->getOrders(); // Make a copy of the list to avoid iterator issues
using namespace std;
// default order constructors:
// generic order
Order::Order(){
setOrderType("Generic");
setIsExecuted(false);
}
// order with type
Order::Order(string orderType){
this->setOrderType(orderType);
setIsExecuted(false);
}
//Overriden stringToLog() method fromILoggable
string Order::stringToLog() {
string log = "Observing Issueing Orders Phase information is: \n Orders: " + orderType;
return log;
}
// deploy order
DeployOrder::DeployOrder()
: Order("Deploy") {}
// advance order
AdvanceOrder::AdvanceOrder()
: Order("Advance") {}
// bomb order
BombOrder::BombOrder()
: Order("Bomb") {}
// blockade order
BlockadeOrder::BlockadeOrder()
: Order("Blockade") {}
// airlift order
AirliftOrder::AirliftOrder()
: Order("Airlift") {}
// negotiate order
NegotiateOrder::NegotiateOrder()
: Order("Negotiate") {}
// copy constructor
Order::Order(Order &o)
{
setOrderType(o.getOrderType());
}
string Order::getOrderType() { return orderType; }
void Order::setOrderType(string type) { orderType = type; }
bool Order::getIsExecuted() { return isExecuted; }
void Order::setIsExecuted(bool isExecuted) { this->isExecuted = isExecuted; }
bool Order::validate()
{
return true;
}
void Order::execute()
{
if(validate())
{
cout << "Executing " << this->orderType << std::endl;
setIsExecuted(true);
}
}
// stream operator order
std::ostream & operator << (std::ostream& os, Order & order)
{
os << "This is a " << order.getOrderType() << " order. ";
if(order.getIsExecuted())
{
os << "Order was executed";
}
os << std::endl;
return os;
}
// assignment operater order
Order& Order::operator=(Order& o)
{
o.setOrderType(getOrderType());
o.setIsExecuted(getIsExecuted());
return *this;
}
// Order list:
// default constructor
OrdersList::OrdersList(){
cout<<"OrderList Constructer here!"<<endl;
}
// destructor
OrdersList::~OrdersList()
{
for (Order *order : orders) {
delete order;
}
orders.clear();
}
// copy constructor
OrdersList::OrdersList(OrdersList &ol)
{
this->orders = ol.getOrders();
}
// stream operator order list
ostream& operator<<(ostream& os, OrdersList & ol)
{
int i = 0;
for (Order *order : ol.getOrders())
{
os << ++i << ": ";
os << *order ;
}
return os;
}
vector<Order *> OrdersList::getOrders()
{
return this->orders;
}
Order* OrdersList::createOrder(std::string orderType)
{
Order *newOrder;
if(orderType == "Deploy")
{
newOrder = new DeployOrder();
}
else if(orderType == "Advance")
{
newOrder = new AdvanceOrder();
}
else if(orderType == "Bomb")
{
newOrder = new BombOrder();
}
else if(orderType == "Blockade")
{
newOrder = new BlockadeOrder();
}
else if(orderType == "Airlift")
{
newOrder = new AirliftOrder();
}
else if(orderType == "Negotiate")
{
newOrder = new NegotiateOrder();
}
else
{
newOrder = new Order();
}
this->addOrder(newOrder);
return newOrder;
}
void OrdersList::addOrder(Order *order)
{
orders.push_back(order);
Notify();
}
void OrdersList::move(int initialListPosition, int targetListPosition)
{
// verifiy that the index positions are valid
int listSize = orders.size();
if(initialListPosition > listSize || initialListPosition < 1 || targetListPosition > listSize || targetListPosition < 1)
{
cout << "Invalid move" << std::endl;
}
else
{
// remove the order
vector<Order *>::iterator itr1 = orders.begin();
advance(itr1,initialListPosition-1);
Order * o = *itr1; // save a pointer to the order before removing it
orders.erase(itr1);
// add it back in the new index
vector<Order*>::iterator itr2 = orders.begin();
advance(itr2,targetListPosition-1);
orders.insert(itr2, o);
cout << "Order moved" << std::endl;
}
}
void OrdersList::remove(int listPosition)
{
vector<Order *>::iterator itr = orders.begin();
advance(itr,listPosition-1);
orders.erase(itr);
cout << "Order removed" << std::endl;
}
void OrdersList::printOrdersList()
{
int i = 0;
for (Order *order : orders)
{
cout << ++i << ": ";
cout << *order ;
}
}
// assignment operater order
OrdersList& OrdersList::operator=(OrdersList& ol)
{
for (Order* order : ol.getOrders()) {
// Assuming that Order has a copy constructor
orders.push_back(new Order(*order));
}
return *this;
}
void OrdersList::Attach(Observer* o){
observers->push_back(o);
cout << "im attaching"<<endl;
}
//Implementation of Remove method (removes an observer from the observers list)
void OrdersList::Detach(Observer* o){
observers->remove(o);
}
//Implementation of the Notify method (will call on the observers update method)
void OrdersList::Notify(){
list<Observer*>::iterator i = observers->begin();
for(;i != observers->end(); ++i){
//using "this" to pass the subject to the update method
cout << "im notifying"<<endl;
(*i)->Update(this);
}
}
Aucun commentaire:
Enregistrer un commentaire