Re: Templated classes with virtual functions
In article
<992700a9-e6e2-461d-99e7-443a7474b1a7@g28g2000yqh.googlegroups.com>,
JoshG <inbilla@gmail.com> wrote:
Hi there,
I'm trying to get the following code to work:
[begincode]
class ReferenceBase
{
public:
virtual ~ReferenceBase()
{
}
void MarkResolved(bool bResolved)
{
OnResolved();
}
virtual void OnResolved()
{
// Do nothing
}
};
template <class ReferrerType>
struct ReferrerTraits
{
typedef void (ReferrerType::*CallbackType)(ReferenceBase*
pkReference);
};
template <class ReferrerType, typename
ReferrerTraits<ReferrerType>::CallbackType ReferrerCallback>
class Reference : public ReferenceBase
{
virtual void OnResolved()
{
if (m_referrer)
{
(m_referrer->*ReferrerCallback)(this);
}
}
void SetReferrer(ReferrerType* referrer)
{
m_referrer = referrer;
}
private:
ReferrerType* m_referrer;
};
class Referrer
{
void OnReferenceResolved(Reference* pReference)
change the above to:
void OnReferenceResolved(ReferenceBase* pReference)
{
// Do something
}
typedef Reference<Referrer, &Referrer::OnReferenceResolved>
ObjectReference;
ObjectReference m_objectReference;
}
[endcode]
Ok, so I am basically trying to setup a set of classes whereby I have
a reference to something that needs resolving. Every now and again, an
application process will resolve these references and call
"MarkResolved" on the ones it resolves. This should in turn call
OnResolved.
The idea is that the objects that own these references will be able to
listen in to when these references are resolved via a templated
version of the reference class and a compiletime assigned callback
function.
This sounds like the Observer pattern, except your solution only allows
for one observer.
Here is the regular, non-templated way to do it using a pull model.
There a lot of different ways to implement an observer, but here is one
that is quick and easy to code up and easy to understand.:
[begin code]
// boilerplate
class Subject;
class Observer {
public:
virtual ~Observer() { }
private:
friend class Subject;
virtual void update() = 0; // only Subjects should call this function
};
class Subject {
set<Observer*> observers;
public:
virtual ~Subject() { }
void attach(Observer* o) { observers.insert(o); }
void detach(Observer* o) { observers.erase(o); }
void notify() {
for_each(observers.begin(), observers.end(),
mem_fun(&Observer::update));
}
};
// end boilerplate, begin custom code for the problem space
class NeedsResolving : public Subject {
bool r;
public:
NeedsResolving(): r(false) { }
void resolve() {
if (!r) {
r = true;
notify();
}
}
void unresolve() {
if (r) {
r = false;
notify();
}
}
bool isResolved() const { return r; }
};
class WantsToSeeResolution : public Observer {
NeedsResolving* observed;
public:
WantsToSeeResolution(NeedsResolving* o): observed(o) {
observed->attach(this);
}
~WantsToSeeResolution() {
if (observed)
observed->detach(this);
}
private:
void update() {
if (!observed) throw logic_error("what am I observing?");
if (observed->isResolved())
cout << "it got resolved\n";
else
cout << "it's not resolved anymore\n";
}
};
int main()
{
NeedsResolving nr;
WantsToSeeResolution wtsr(&nr);
// observer must outlive observed in this model,
// but that can be changed.
nr.resolve();
nr.unresolve();
}
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]