alternative to RTTI needed

  • Thread starter Maurice Termeer
  • Start date
M

Maurice Termeer

Hi, suppose I have an abstract base class called shape and lots of
subclasses like square, circle, triangle and such. These subclasses may
have subclasses themselves as well, but shape is on top of the
inheritance tree.

Now suppose I want to write a different component to draw these shapes.
By different component I really mean different, so the whole
datastructure can be used by other programs that do not know about the
drawing component. And second, the drawing component may not be able to
draw all shapes. My question is, how should the drawing component look like?

Right now I have something like:

class ShapeDrawer {
void draw(shape *p) {
if (typeid(p) == typeid(circle))
draw(dynamic_cast<circle>(p));

else if (typeid(p) == typeid(triangle))
draw(dynamic_cast<triangle>(p));

else ...
}

void draw(circle *p) { ... }
void draw(triangle *p) { ... }
}

This works, but doesn't look nice. I don't like the overhead of the
draw(shape *p) function. Is there a way to let the compiler do this? Of
course making draw a virtual function of shape would solve it all, but
that is not possible since it really need to be separate components.

Maurice Termeer
 
A

Attila Feher

Maurice said:
Hi, suppose I have an abstract base class called shape and lots of
subclasses like square, circle, triangle and such. These subclasses
may have subclasses themselves as well, but shape is on top of the
inheritance tree.

Now suppose I want to write a different component to draw these
shapes.
By different component I really mean different, so the whole
datastructure can be used by other programs that do not know about the
drawing component. And second, the drawing component may not be able
to draw all shapes. My question is, how should the drawing component
look like?
[SNIP]

As far as I can tell, you are looking for the Visitor pattern.

http://www.drbob42.com/cbuilder/patterns.htm
 
M

Maurice Termeer

Attila said:
Maurice said:
Hi, suppose I have an abstract base class called shape and lots of
subclasses like square, circle, triangle and such. These subclasses
may have subclasses themselves as well, but shape is on top of the
inheritance tree.

Now suppose I want to write a different component to draw these
shapes.
By different component I really mean different, so the whole
datastructure can be used by other programs that do not know about the
drawing component. And second, the drawing component may not be able
to draw all shapes. My question is, how should the drawing component
look like?

[SNIP]

As far as I can tell, you are looking for the Visitor pattern.

http://www.drbob42.com/cbuilder/patterns.htm

Hm, although that is a better solution than mine, I still don't really
like it. It's kind a general structure to solve this problem, but it
still remains a hack. I would actually want to type something like

void draw(shape *p) {
draw(dynamic_cast<typeid(p)>(p));
}

but c++ won't let me.
 
A

Attila Feher

Maurice said:
Attila Feher wrote: [SNIP]
As far as I can tell, you are looking for the Visitor pattern.

http://www.drbob42.com/cbuilder/patterns.htm

Hm, although that is a better solution than mine, I still don't really
like it. It's kind a general structure to solve this problem, but it
still remains a hack. I would actually want to type something like

void draw(shape *p) {
draw(dynamic_cast<typeid(p)>(p));
}

but c++ won't let me.

It is s much a heck, that it is a Design Pattern, one of the first ones.
You probably want to look at that book:

http://www.amazon.com/exec/obidos/tg/detail/-/0201715945/qid=1097059720/sr=8
-2/ref=pd_csp_2/103-0081174-9277466?v=glance&s=books&n=507846

or

http://tinyurl.com/43r5l

A Design Pattern is (per definition) the opposite to a hack.
 
P

Patrick Kowalzick

Dear Maurice,

do you have a copy of "Modern C++ Design" from Andrei Alexandresci? If yes,
just read the chapters about double dispatching. It is not fitting perfectly
but some techniches you could use a described nicely. If you do not have a
copy, take a look inside the dispatching functions in the Loki library which
acompanies the book (http://sourceforge.net/projects/loki-lib/).

If I have some time, I can give you a more extensive answer.

Regards,
Patrick
 
R

Rolf Magnus

Attila said:
Maurice said:
Attila Feher wrote: [SNIP]
As far as I can tell, you are looking for the Visitor pattern.

http://www.drbob42.com/cbuilder/patterns.htm

Hm, although that is a better solution than mine, I still don't really
like it. It's kind a general structure to solve this problem, but it
still remains a hack. I would actually want to type something like

void draw(shape *p) {
draw(dynamic_cast<typeid(p)>(p));
}

but c++ won't let me.

It is s much a heck, that it is a Design Pattern, one of the first ones.
You probably want to look at that book:

http://www.amazon.com/exec/obidos/tg/detail/-/0201715945/qid=1097059720/sr=8
-2/ref=pd_csp_2/103-0081174-9277466?v=glance&s=books&n=507846

or

http://tinyurl.com/43r5l

A Design Pattern is (per definition) the opposite to a hack.

No. A design pattern is just a hack that is so commonly used that it got
written down as a standard way of solving a problem. That, however, doesn't
mean it's not a hack anymore. Well, I'd not consider all patterns hacks,
but the visitor pattern is not really elegant. Unfortunately, there doesn't
seem to be an elegant C++ solution to the OP's problem.
 
T

Tom Widmer

Attila said:
Maurice said:
Hi, suppose I have an abstract base class called shape and lots of
subclasses like square, circle, triangle and such. These subclasses
may have subclasses themselves as well, but shape is on top of the
inheritance tree.

Now suppose I want to write a different component to draw these
shapes.
By different component I really mean different, so the whole
datastructure can be used by other programs that do not know about the
drawing component. And second, the drawing component may not be able
to draw all shapes. My question is, how should the drawing component
look like?

[SNIP]

As far as I can tell, you are looking for the Visitor pattern.

http://www.drbob42.com/cbuilder/patterns.htm

Hm, although that is a better solution than mine, I still don't really
like it. It's kind a general structure to solve this problem, but it
still remains a hack. I would actually want to type something like

void draw(shape *p) {
draw(dynamic_cast<typeid(p)>(p));
}

but c++ won't let me.

That's because you are trying to mix static and dynamic typing. The
above would have to generate a *lot* of code. Note that there are good
generic implementations of the visitor pattern around; check out Loki:
http://sourceforge.net/projects/loki-lib

With that, you won't need to implement any of the boiler-plate code
yourself.

Tom
 
A

Attila Feher

Rolf Magnus wrote:
[SNIP]
No. A design pattern is just a hack that is so commonly used that it
got written down as a standard way of solving a problem. That,
however, doesn't mean it's not a hack anymore. Well, I'd not consider
all patterns hacks, but the visitor pattern is not really elegant.
Unfortunately, there doesn't seem to be an elegant C++ solution to
the OP's problem.

Design Patterns are OW for Good Practice. Hack is the opposite of it. Hack
suggests temporary, not scaling, going-against-the-wind,
only-one-understands etc. Design Patterns are the complete opposite of
that. IIRC there is something called Acyclic Visitor, which is regarded by
many as "what the Visitor pattern really ought to be".

http://www.objectmentor.com/resources/articles/acv.pdf

Maybe that one you do not feel so much of a hack?
 
?

=?ISO-8859-1?Q?Tobias_G=FCntner?=

Of
course making draw a virtual function of shape would solve it all, but
that is not possible since it really need to be separate components.

How separate? Does MI solve your problem?

class Shape
{
public:
virtual ~Shape(){}
};

class DrawableShape
{
public:
virtual void Draw() const = 0;
};

class Circle : public Shape, public DrawableShape
{
virtual void Draw() const
{
foo();
}
};

void Draw(const Shape* s)
{
const DrawableShape* ds = dynamic_cast<const DrawableShape*>(s);
if(ds)
ds->Draw();
}

Of course this requires that you are able to change all shape classes to
inherit from DrawableShape. If this is not possible, the Visitor Pattern
might be more suitable.
 
?

=?ISO-8859-1?Q?=22Nils_O=2E_Sel=E5sdal=22?=

Maurice said:
Hi, suppose I have an abstract base class called shape and lots of
subclasses like square, circle, triangle and such. These subclasses may
have subclasses themselves as well, but shape is on top of the
inheritance tree.

Now suppose I want to write a different component to draw these shapes.
By different component I really mean different, so the whole
datastructure can be used by other programs that do not know about the
drawing component. And second, the drawing component may not be able to
draw all shapes. My question is, how should the drawing component look
like?

Right now I have something like:

class ShapeDrawer {
void draw(shape *p) {
if (typeid(p) == typeid(circle))
draw(dynamic_cast<circle>(p));

else if (typeid(p) == typeid(triangle))
draw(dynamic_cast<triangle>(p));

else ...
}

void draw(circle *p) { ... }
void draw(triangle *p) { ... }
}
When people do these sort of things they usually flesh out
the drawer as a seperate object, as it seems you have done.
However let each shape have a draw method:

class Drawer {
draw(Cicle *p);
draw(Rectangle *p);
}

A Shape would have a
void draw(Drawer* d); abstract method, and
the draw implementation of Triangle would just do

void Triangle::draw(Drawer *d){
d->draw(this);
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top