I'm writing an Observer Pattern program that uses an UpperCaseMonitor subject or concrete subject to monitor when there is an uppercase letter in a line of text entered by the user. Everything seems to work fine until i try to access the state changes to keep count, store, and print out in the the "show_data()" methods of the CountingObserver and AccumulatingObserver classes. Whenever an uppercase letter is entered a window comes up saying the program has stopped running, so I know it's some kind of run-time error. After debugging it I'm pretty sure the error is in the "char value = _subject->get_state();" statement, but I can't figure out what to change to fix the problem. When I comment out that line in the show_data() methods the program will run, but I need it or some other way to access the states so I can store and output them. My code is below.
#include <iostream>
#include <vector>
#include <list>
#include <cctype>
using namespace std;
class Observer;
//===========================================================================
class Observable
{
public:
virtual void attach(Observer*) = 0;
virtual void detach(Observer*) = 0;
virtual void notify() = 0;
// Can we get rid of these?
virtual char get_state() = 0;
virtual void set_state(char) = 0;
};
class Observable;
//===========================================================================
class Observer
{
public:
virtual void update(Observable*) = 0;
};
//Objects of this type maintain a state whose value is an upper-case character.
//Objects of this type can be observed by objects that are interested in this object's state.
class UpperCaseMonitor : public Observable
{
public:
void attach(Observer*); //Add the parameter to the list of objects that are observing this object
void detach(Observer*); //Remove the parameter from the list of objects that are observing this object
virtual void notify(); //Performs the notify-type behavior of the observer pattern
virtual char get_state() {return _state; } //Usual access-type behavior
virtual void set_state(char new_state) {_state = new_state; notify();} //Usual mutator-type behavior
void watch(char); //If the parameter is an uppercase character the object's state becomes the value of the parameter.
private:
vector<Observer*> _observers;
char _state;
};
//An object of this type maintains a count only of the state changes of the object it observes.
class CountingObserver : public Observer
{
public:
CountingObserver(UpperCaseMonitor *);
CountingObserver();
~CountingObserver();
virtual void update(Observable*);//Respond to a change of state in the object being observed
void show_data();//Output a brief message and the maintained value
//private:
UpperCaseMonitor *_subject;
int state_count;
};
//An object of this type stores all states the object it observes has had (since it registered with the object it observed).
class AccumulatingObserver : public Observer
{
public:
AccumulatingObserver(UpperCaseMonitor *);
AccumulatingObserver();
~AccumulatingObserver();
virtual void update(Observable*);//Respond to a change of state in the object being observed
//private:
UpperCaseMonitor *_subject;
void show_data();//Output a brief message and the maintained values in sequence starting with the first.
};
void process_input(char chr);
int main(){
// Monitor for uppercase chars
UpperCaseMonitor uc_monitor;
// Want to be notified when there's an upper case char
CountingObserver observer1;
AccumulatingObserver observer2;
// Get registered
uc_monitor.attach(&observer1);
uc_monitor.attach(&observer2);
// Prompt
cout << "Enter some text, type ^d when done.\n";
// Process text
char chr;
while (cin.get(chr))
{
uc_monitor.watch(chr);
process_input(chr);
}
// See what observers know
observer1.show_data();
observer2.show_data();
}
void process_input(char chr)
{
// Maybe do something with the input
}
void UpperCaseMonitor::attach(Observer* obs)
{
_observers.push_back(obs);
}
void UpperCaseMonitor::detach(Observer* obs)
{
int count = _observers.size();
int i;
for(i = 0; i < count; i++)
{
if(_observers[i] == obs)
break;
}
if(i < count)
_observers.erase(_observers.begin() + i);
}
void UpperCaseMonitor::notify()
{
int count = _observers.size();
for (int i = 0; i < count; i++)
(_observers[i])->update(this);
}
void UpperCaseMonitor::watch(char chr)
{
if (isupper(chr))
{
set_state(chr);
}
}
CountingObserver::CountingObserver(UpperCaseMonitor *s)
{ state_count = 0;
_subject = s;
_subject->attach(this);
}
CountingObserver::CountingObserver()
{
state_count = 0;
}
CountingObserver::~CountingObserver()
{
_subject->detach(this);
}
void CountingObserver::update(Observable* ChangedState)
{
if(ChangedState = _subject)
show_data();
}
void CountingObserver::show_data()
{
char value = _subject->get_state();
state_count += 1;
cout << "Number of state changes is " << state_count << " and most recent state change is " << endl; //value << endl;
}
AccumulatingObserver::AccumulatingObserver(UpperCaseMonitor *s)
{
_subject = s;
_subject->attach(this);
}
AccumulatingObserver::AccumulatingObserver()
{
}
AccumulatingObserver::~AccumulatingObserver()
{
_subject->detach(this);
}
void AccumulatingObserver::update(Observable* ChangedState)
{
if(ChangedState = _subject)
show_data();
}
void AccumulatingObserver::show_data()
{
//char value = _subject->get_state();
list<char> charList;
/*
for( int i=0; i < 10; i++ ) {
charList.push_front(value);
}*/
cout << "Maintained states: " << endl;
// Display the list
list<char>::iterator theIterator;
for( theIterator = charList.begin(); theIterator != charList.end(); theIterator++ ) {
cout << *theIterator;
}
}