I'm trying to create a subject-observers system in C++, like the events system in C#. the observer class:
template <class T>
class Observer {
int id;
public:
static int nextId;
Observer() : id(nextId++) {}
virtual void handleEvent(const T&) = 0;
virtual ~Observer();
};
the subject class:
template<class T>
class Subject {
set<shared_ptr<Observer<T>>> observers;
public:
Subject() : observers() {}
void notify(const T&);
void addObserver(Observer<T>& );
void removeObserver(Observer<T>&);
Subject<T>& operator+=(Observer<T>&);
Subject<T>& operator-=(Observer<T>&);
Subject<T>& operator()(const T&);
};
the problem is when I try to implement addObserver
I don't know how to add the reference to the set.
I understand make_shared<Observer<T>>
is creating a new instance, so when I tried make_shared<Observer<T>>(observer)
I got an error of trying to create an abstract class :
error: invalid new-expression of abstract class type ‘Observer’
I tried shared_ptr<Observer<T>> observerPtr(observer)
and it did not work as well :
error: no matching function for call to ‘std::shared_ptr >::shared_ptr(Observer&)’
how can I create a shared_ptr
from a reference of an object derived from an abstract class?
what I'm trying to achieve is make this example work:
class TemperatureSensor : public Subject<int> {};
class AirConditioner : public Observer<int> {
static int nextId;
int id;
void onTemperatureChange(int temperature){
std::cout << "Air Conditioner #" << id << " got a report from TemperatureSensor, reading " << temperature << std::endl;
}
public:
AirConditioner() : Observer() {
id = (++nextId);
}
void handleEvent(const int& param) override {
onTemperatureChange(param);
}
};
int AirConditioner::nextId = 0;
int main(){
TemperatureSensor s;
AirConditioner a,b,c;
(((s += a) += b) += c);
s(42); // Should print:
// Air Conditioner #1 got a report from TemperatureSensor, reading 42
// Air Conditioner #2 got a report from TemperatureSensor, reading 42
// Air Conditioner #3 got a report from TemperatureSensor, reading 42
}
To answer your question regarding implementing addObserver, the easiest way to get it work is to store the pointer in the container:
template<class T>
class Subject {
set<Observer<T>*> observers;
public:
Subject() : observers() {}
void addObserver(Observer<T>& o) { observers.insert(&o); }
Depending on how you wish to manage the life cycle of the observer object, you could use set<shared_ptr<Observer<T>>>
, but in this case, you should pass the share_ptr<Observer<T>>
as parameter of addObserver(shared_ptr<Observer<T>>& o)
. If you have to use addObserver(Observer<T>&)
interface and you want the "observers" set to co-manage the life cycle of the observer object, you could use std::enable_shared_from_this and make Observer a subclass of std::enable_shared_from_this.
Hope this helps.