Reputation:
I am having a bit of trouble with observer pattern I have a beverage class that uses decorator fine. I am trying to implement observer to let an observer( say a cell phone/text message) in this case know when there order is done. i wont include the beverage/decorator classes since they work fine.
In main i was going to do something like this:
Subject mySubject = new Subject();
Observer myObserver1 = new Observer1();
Observer myObserver2 = new Observer2();
// register observers
mySubject.Register(myObserver1);
mySubject.Register(myObserver2);
mySubject.Notify("message 1");
mySubject.Notify("message 2");
I have a subject class, observer, phone behavior class and a cellhone1,cellphone2 classes..
Here is the subject class
#ifndef _SUBJECT_
#define _SUBJECT_
//#include "Starbuzz.h"
//#include "Starbuzz2.h"
#include "Observer.h"
#include <list>
namespace CoffeeHouse {
namespace Observers {
class Subject {
private:
std::list< Observer* > observers;
public:
Subject();
~Subject();
void Subject::Register(Observer observer)
{
//if (!observers.(observer))
//{
observers.insert(observer);
}
//}
//void Unregister(Observer observer)
//{
// if observer is in the list, remove
//if (observers.Contains(observer))
//{
//observers.Remove(observer);
//}
//}
void Notify(std::string message)
{
//need loop
Observer observer;
observer.update(message);
}
//}
//}
//void Subject::registerObserver( Observer* o ) { assert( o );
//_observers.push_front(o);
//}
//void Subject::removeObserver( Observer* o ) { assert( o );
// _observers.remove(o);
//}
//void Subject::notifyObservers() const {
//for( std::list< Observer* >::iterator iterator = _observers.begin(); _observers.end() != iterator; ++iterator ) {
//Observer* observer = *iterator;
//observer->update(message);
//}
//}
};
} // namespace Observer
}
#endif
Here is the observer class
#ifndef _OBSERVER_
#define _OBSERVER_
#include <string>
namespace CoffeeHouse {
namespace Observers {
class Subject;
class Observer {
//public: virtual ~Observer() = 0;
public: virtual void Update(std::string message) = 0;
};
here is the phone behavior class
#ifndef _PHONEBEHAVIOR_
#define _PHONEBEHAVIOR_
namespace CoffeeHouse {
namespace Observer {
class PhoneBehavior {
public: virtual void Update() const = 0;
};
protected: virtual ~PhoneBehavior() = 0 {
};
};
} // namespace Observer
} //
here is cellphone 1
#ifndef _CELLPHONE1_
#define _CELLPHONE1_
namespace CoffeeHouse {
namespace Observer {
include<iostream>
class CellPhone1: public Observer, public PhoneBehavior {
public:
CellPhone1();
~CellPhone1();
virtual void Update(std::string message)
{
std::cout << "CellPhone1: " << message;
}
};
} // namespace Observer
} //
#endif
here re the errors i am getting..
error C2259: 'CoffeeHouse::Observers::Observer' : cannot instantiate abstract class
1> due to following members:
1> 'void CoffeeHouse::Observers::Observer::update(std::string)' : is abstract
see declaration of 'CoffeeHouse::Observers::Observer::update'
error C2661: 'std::list<_Ty>::insert' : no overloaded function takes 1 arguments
with[_Ty=CoffeeHouse::Observers::Observer *
error C2259: 'CoffeeHouse::Observers::Observer' : cannot instantiate abstract class
due to following members:
'void CoffeeHouse::Observers::Observer::update(std::string)' : is abstract
observer.h(15) : see declaration of 'CoffeeHouse::Observers::Observer::update
When i click on error "cannot instantiate abstract class" it takes me to:
void Subject::Register(Observer observer)
I understand that Abstract classes are made such that they cannot be instantiated!
How could i do an update then?? any suggestions of a better way?
I appreciate any help!
Upvotes: 0
Views: 1620
Reputation: 31
You can make anything observable with this:
https://simmesimme.github.io/tutorials/2015/09/20/signal-slot
#ifndef SIGNAL_H
#define SIGNAL_H
#include <functional>
#include <map>
//! A signal object may call multiple slots with the same
//! signature. You can connect functions to the signal which will be
//! called when the emit() method on the signal object is invoked. Any
//! argument passed to emit() will be passed to the given functions.
template <typename... Args>
class signal
{
public:
//! Default constructor.
signal(): m_slots(), m_current_id(0) {}
//! Copy constructor. (deleted)
signal(signal const& other) = delete;
//! Assignment operator. (deleted)
signal& operator=(signal const& other) = delete;
//! Connects a member function to this signal.
//!
//! @code{.cpp}
//! signal<> s;
//! int id = s.connect_member(&myclass, MyClass::method);
//! @endcode
//!
//! @param[in] instance Pointer to the instance to connect.
//! @param[in] func Pointer to the member func to connect.
//! @return id of object connected, to be used to disconnect.
template <typename T>
int connect_member(T *inst, void (T::*func)(Args...))
{
return connect([=](Args... args) {(inst->*func)(args...);});
}
//! Connects a const member function to this signal.
//!
//! @code{.cpp}
//! signal<> s;
//! int id = s.connect_member(&myclass, MyClass::method);
//! @endcode
//!
//! @param[in] instance Pointer to the instance to connect.
//! @param[in] func Pointer to the member func to connect.
//! @return id of object connected, to be used to disconnect.
template <typename T>
int connect_member(T *inst, void (T::*func)(Args...) const)
{
return connect([=](Args... args) { (inst->*func)(args...);});
}
//! Connects a std::function function wrapper to this signal.
//!
//! This method can be used to adapt many kinds of callable objects
//! to a signal.
//!
//! @code{.cpp}
//! signal<> s;
//! std::function<void()> f = std::bind(&signal_utest::test0, this);
//! int id = s.connect(f);
//! @endcode
//!
//! @param[in] slot Function object invoked on emit().
//! @return id of object connected, to be used to disconnect.
int connect(std::function<void(Args...)> const& slot) const
{
m_slots.insert(std::make_pair(++m_current_id, slot));
return m_current_id;
}
//! Disconnects a previously connected function.
//!
//! @param[in] id Id returned by connect function.
void disconnect(int id) const
{
m_slots.erase(id);
}
// Disconnects all previously connected functions.
void disconnect_all() const
{
m_slots.clear();
}
//! Calls all connected functions.
void emit(Args... p)
{
for (auto it : m_slots)
it.second(p...);
}
private:
mutable std::map<int, std::function<void(Args...)>> m_slots;
mutable int m_current_id;
};
#endif /* SIGNAL_H */
with tests:
signal<> s0;
int id0 = -1;
UTEST_CHECK(id0 != 1);
id0 = s0.connect_member(this, &signal_utest::test0);
UTEST_CHECK(id0 == 1);
UTEST_CHECK(get_test0() == 0);
s0.emit();
UTEST_CHECK(get_test0() == 1);
signal<int> s1;
UTEST_CHECK(s1.connect_member(this, &signal_utest::test1) == 1);
UTEST_CHECK(test1() == 0);
s1.emit(1);
UTEST_CHECK(test1() == 1);
signal<int, int> s2;
UTEST_CHECK(s2.connect_member(this, &signal_utest::test2) == 1);
UTEST_CHECK(test2() == 0);
s2.emit(1, 1);
UTEST_CHECK(test2() == 2);
Upvotes: 0
Reputation: 13026
One error is that Subject::Register is currently taking an Observer object, instead of a pointer to an Observer. This means that you're trying to instantiate an abstract object, which is illegal.
Upvotes: 1
Reputation: 3609
Problems I see:
Observer
in PhoneBehavior
and CellPhone1 class source files.#include <string>
or use the
std namespace for the string in void
Update(string message)
virtual void update()
should have
probably have a capital "U" to stay
consistent with your coding style and
because that's how it's called in the
CellPhone1 class source file.Cout <<"CellPhone1:" + message);
. It should be std::cout << "CellPhone1: " << message;
#include <iostream>
class PhoneBehavior
should have a semicolon after it.Edit: When I say "class source file" I'm assuming your project setup with CellPhone1.cpp , PhoneBehavior.cpp files based on the way you presented your question.
Upvotes: 1