The files observer0.h and tobserver0.C contain the example from the book (p. 262).
It is mentioned in the book that the solution is restricted by the requirement that all observers of a single observable must be of the same type.
In the files observer1.h and tobserver1.C a more general solution can be found.
The technique from observer1.h can be used in general to build heterogeneous containers of objects of different unrelated types that support a common interface.
The idea is the following:
AC
(for ``Abstract Class'') that
declares the interface using pure virtual member declarations.
class AC {
public:
virtual int f(int) = 0;
};
AC
pointers, e.g.
vector<AC*> container;
C
that
supports the AC
interface with minimal fuss, e.g. by writing something like
C c(..);
D d(..); // D and C not related through inheritance.
container.push_back(&c);
container.push_back(&d);
This would be possible if C
and D
would be subclasses of AC
,
but they are not.
C'
derived from
AC
which wraps around
a C
object:
class C': public AC {
public:
C'(C& c): c_(&c) {}
int f(int i) { return c_->f(i); }
private:
C* c_;
};
With this, we could write
container.push_back(new C'(c));
D
and any class
supporting the AC
interface, it suffices to replace
C'
by a class template
ACT
.
template<class X>
class ACT: public AC {
public:
ACT(X& x): x_(&x) {}
int f(int i) { return x_->f(i); }
private:
X* x_;
};
Now we can write:
container.push_back(new ACT<C>(c));
container.push_back(new ACT<D>(d));
and, e.g.,
for_each(container.begin(), container.end(), mem_fun(&AC::notified));
As a real example, the code from
observer1.h
is reproduced below.
#ifndef OBSERVER_H
#define OBSERVER_H
#include <list>
#include <functional>
#include <algorithm>
class AbstractObserver {
public:
virtual void notified() = 0;
};
template <class T>
class Observer: public AbstractObserver {
public:
Observer(T& t): t_(&t) {}
void notified() { t_->notified(); }
private:
T* t_;
};
// An Observable has a number of associated Observers that will be
// warned using Observer::notified() each time the Observable changes
// state.
class Observable {
public:
template <class T>
void add_observer(T& observer) {
observers_.push_back(new Observer<T>(observer)); }
void remove_observer(AbstractObserver& observer) {
observers_.remove(&observer); }
protected: // an observable that changes state will call notify()
void notify() {
for_each(observers_.begin(), observers_.end(),
mem_fun(&AbstractObserver::notified));
}
private:
list<AbstractObserver*> observers_;
};
#endif