473,386 Members | 1,699 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

Decoupling classes

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&).

Is there a nice design pattern for doing this? Or an I searching for the
impossible.

Thanks for any advice,
Alan

class A {
};
class V {
public:
virtual void visit(A& a) = 0;
};

class B : public A {
};

class W : public V {
public:
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();

v->visit(*t);
t = &b;
v->visit(*t);

return 0;
}
Apr 25 '06 #1
4 2698
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&).

Is there a nice design pattern for doing this? Or an I searching for
the impossible.

Thanks for any advice,
Alan

class A {
};
class V {
public:
virtual void visit(A& a) = 0;
};

class B : public A {
};

class W : public V {
public:
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();
Did you mean

V *v = new W();

? You would probably need a virtual destructor in 'V', of course.
It doesn't really matter, though. What you're trying to do _is_
impossible.
v->visit(*t);
t = &b;
v->visit(*t);
No matter how you slice it, the type of 't' is A*. There is no way
for the program to learn where 't' came from. If 'A' or 'B' _were_
polymorphic types, one could try using 'dynamic_cast', yet it might
still fail (say, if 't' is part of another class deriving from 'A').

Double dispatch would help, if you allow that 'B' could know about 'W'.
return 0;
}


What problem are you trying to solve? Perhaps it's possible to do
using templates?

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Apr 25 '06 #2
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&).

Is there a nice design pattern for doing this? Or an I searching for the
impossible.

Thanks for any advice,
Alan

class A {
};
class V {
public:
virtual void visit(A& a) = 0;
};

class B : public A {
};

class W : public V {
public:
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();

v->visit(*t);
t = &b;
v->visit(*t);

return 0;
}


The "problem" is that you have used a polymorphic reference to treat
your B object as an A object. Thus, the best function overload for
W::visit() is the one that accepts an A-reference. If you instead
passed a B-reference directly, it would happily use the other overload.
If you can't make such a change, you'll have to either downcast using
dynamic_cast to regain the lost type information or redesign. The
dynamic_cast, BTW, would not need to be present in V since W can
override the virtual function that accepts an A-reference. (The
B-reference overload obviously cannot be called with a V object except
where the B object is treated as an A, so V would still be ignorant of
B and W types.)

Cheers! --M

Apr 25 '06 #3
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
Apr 25 '06 #4
Victor Bazarov wrote:
Alan Woodland wrote:
snip
W *v = new W();


Did you mean

V *v = new W();

Yes, sorry
? You would probably need a virtual destructor in 'V', of course.
It doesn't really matter, though. What you're trying to do _is_
impossible. It's as I feared then :( I was just trying to keep the example shorter.
v->visit(*t);
t = &b;
v->visit(*t);


No matter how you slice it, the type of 't' is A*. There is no way
for the program to learn where 't' came from.

Yes, I was hoping there was a gem of wisom that could make it appear
like to not be.
If 'A' or 'B' _were_
polymorphic types, one could try using 'dynamic_cast', yet it might
still fail (say, if 't' is part of another class deriving from 'A'). Yes, thats not too much of a problem though, I can handle that.
Double dispatch would help, if you allow that 'B' could know about 'W'. I thought double dispatch required A knowing about W too? It's fine for
B to know about W I think - they'll both be being compiled into the same
shared object. (See below)
What problem are you trying to solve? Perhaps it's possible to do
using templates?


I've got a group of Data structures that extend one base class. I've
written all the code so far to be very modular, and load a series of
plugins using shared objects (which works beautifuly). The problem now
though is that I want there to be output plugins that can do various
different types of output (e.g, rendering to OpenGL, saving to XML file
etc.) without ending up tying the Data structures to the output type.
The problem is though that the data structures themselves get extended
by some plugins, so adding a 'virtual void render(DataStructure& ds) =
0' pure virtual method in the base class for the OutputPlugin will only
result in the output plugin being aware of the basic information, not
the fact that it may (or may not) have been subclassed. So to sumarise
the code doesn't really feel like it belongs in a 'virtual void
render()' method in the DataStructure class, and putting it in the
OutputPlugin misses the sub classing.

Alan
Apr 25 '06 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Bob Rock | last post by:
Hello, in the last few days I've made my first few attempts at creating mixed C++ managed-unmanaged assemblies and looking aftwerwards with ILDASM at what is visible in those assemblies from a...
9
by: Aguilar, James | last post by:
I know that one can define an essentially unlimited number of classes in a file. And one can declare just as many in a header file. However, the question I have is, should I? Suppose that, to...
12
by: Langy | last post by:
Hello I'm fairly new to C++ but have programmed several other languages and found most of c++ fairly easy (so far!). I've come to a tutorial on classes, could someone please tell me why you...
3
by: Ken Allen | last post by:
I am relatively new to .Net and C#, but I hav ebeen programing in other languages and done some COM work for a number of years. I am attempting to understand how to map an older program...
2
by: joye | last post by:
Hello, My question is how to use C# to call the existing libraries containing unmanaged C++ classes directly, but not use C# or managed C++ wrappers unmanaged C++ classes? Does anyone know how...
18
by: Edward Diener | last post by:
Is the packing alignment of __nogc classes stored as part of the assembly ? I think it must as the compiler, when referencing the assembly, could not know how the original data is packed otherwise....
0
by: George Sakkis | last post by:
Didn't have much luck in the Django list, so I'm posting it here just in case anyone has come up with this problem. Django maintains two parallel hierarchies of field classes, one related to...
6
by: ivan.leben | last post by:
I want to write a Mesh class using half-edges. This class uses three other classes: Vertex, HalfEdge and Face. These classes should be linked properly in the process of building up the mesh by...
0
by: ivan.leben | last post by:
I am writing this in a new thread to alert that I found a solution to the problem mentioned here: http://groups.google.com/group/comp.lang.c++/browse_thread/thread/7970afaa089fd5b8 and to avoid...
7
by: Sharon | last post by:
Hi. I'm working on an application with a Data Access Layer, API and UI. There are some entity classes defined in the DAL which the UI uses through the API. This means that there is some coupling...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.