473,385 Members | 1,324 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,385 software developers and data experts.

alternative to RTTI needed

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
Jul 22 '05 #1
9 2238
Maurice Termeer wrote:
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

--
Attila aka WW
Jul 22 '05 #2
Attila Feher wrote:
Maurice Termeer wrote:
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.
Jul 22 '05 #3
Maurice Termeer wrote:
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...097059720/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.

--
Attila aka WW
Jul 22 '05 #4
Attila Feher wrote:
Maurice Termeer wrote:
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...097059720/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.

Jul 22 '05 #5
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
"Maurice Termeer" <m.*********@student.tue.nl> wrote in message
news:ck**********@news.tue.nl...
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

Jul 22 '05 #6
On Wed, 06 Oct 2004 11:44:32 +0200, Maurice Termeer
<m.*********@student.tue.nl> wrote:
Attila Feher wrote:
Maurice Termeer wrote:
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
Jul 22 '05 #7
Rolf Magnus wrote:
[SNIP]
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.


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?

--
Attila aka WW
Jul 22 '05 #8
> 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.

--
Regards,
Tobias
Jul 22 '05 #9
Maurice Termeer wrote:
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);
}
Jul 22 '05 #10

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

Similar topics

1
by: MoCha | last post by:
hi all, i want to get the name of the class of an object during run-time. the problem is when i'm using the rtti mechanism of name(), the name is preceded by the length. So, i get something like...
9
by: Rick | last post by:
Hi, I wrote a few classes recently and am writing a small GC implementation for C++. I will be implementing my own gc_ptr type maintain a list where I'll store pointers to allocated memory. I...
6
by: Kleidemos | last post by:
If I implement a simple RTTI system, more simple than C++ RTTI system for my program and this system is plus or minus: #define DEF_RTTI_BASE(name) virtual inline const char *Name(){ return...
9
by: Agoston Bejo | last post by:
Hello there, I would like to know what overheads there are to think of when using RTTI. I understand that enabling RTTI increases the sizes of the classes, but not the objects themselves. This...
2
by: denny | last post by:
Hey all, I know that dynamic_cast<> takes some time, but , for instance, is there a memoy cost associated in with it? Does it have to maintain a table in memory, thus bloating the runtime ram...
3
by: Neo | last post by:
Hi Friends, I have a question about RTTI. 1) In C++ we have vptr pointing to vtables which helps to make use of pointer as polymorphic entities. 2) Without knowing object type I can call methods...
5
by: dotNeter | last post by:
I'm studying the RTTI, and my current work is concern for how to get the self-defined type at runtime, that's exactly what the RTTI does. I mean, in my application, I built several self-defined...
33
by: mscava | last post by:
Well I've got a problem, that is more theoretical than practital. I need to know benefits of RTTI. I see another way of doing it... class A { public: ~virtual A() {} enum Type { X, Y, Z }; ...
2
by: Chameleon | last post by:
I know than dynamic_cast check string name of derived to base class and if one of them match, return the pointer of that object or else zero. I suppose, I dynamic_cast instead of strings, checks...
3
by: lfnovaes | last post by:
Is it possible to get the type of a "unknown" exception using RTTI? Tanks in advance.
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
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:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

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.