Re: Decoupling classes
Alan Woodland wrote:
Hi, I've looked through the FAQ, and I can't seem to find an answer to
this one. Can anyone point me to a design pattern that will produce the
desired behaviour illustrated below please? I know why it doesn't print
"W visiting B", and I've read about double dispatch now too. What I'd
really like though is to keep A and V completely unaware of the
existence of B and W and still end up with "W visiting B" getting
printed. Ideally too I'd like to avoid putting a dynamic_cast in
W::visit(A&).
I don't think those two requirements are compatible - either you need V
to know about both A and B (in which case you have the normal, cyclic
visitor pattern), or you need to use dynamic_cast (in which case you
have the acyclic visitor pattern).
Google for "cyclic visitor" and "acyclic visitor". A good implementation
of both is available as part of the Loki library. See
http://sourceforge.net/projects/loki-lib/
Here's your code in acyclic form:
struct V {
virtual ~V(){}
};
struct Base {
virtual ~Base(){}
virtual void accept(V&) = 0;
};
struct A;
struct AV: public virtual V {
virtual void visit(A& a) = 0;
};
struct A: public Base {
virtual void accept(V& v)
{
if (AV* av = dynamic_cast<AV*>(&v))
av->visit(*this);
}
};
struct B;
struct BV: public virtual V {
virtual void visit(B& b) = 0;
};
struct B : public A {
virtual void accept(V& v)
{
if (BV* bv = dynamic_cast<BV*>(&v))
bv->visit(*this);
}
};
#include <iostream>
struct W : public AV, public BV {
virtual void visit(A& a) {
std::cout << "W visiting A" << std::endl;
}
virtual void visit(B& b) {
std::cout << "W visiting B" << std::endl;
}
};
int main(void) {
B b;
A a;
A *t = &a;
W *v = new W();
t->accept(*v);
t = &b;
t->accept(*v);
std::cin.get();
return 0;
}
Tom