alternative to RTTI needed

Discussion in 'C++' started by Maurice Termeer, Oct 6, 2004.

  1. 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
    Maurice Termeer, Oct 6, 2004
    #1
    1. Advertising

  2. Maurice Termeer

    Attila Feher Guest

    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
    Attila Feher, Oct 6, 2004
    #2
    1. Advertising

  3. 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.
    Maurice Termeer, Oct 6, 2004
    #3
  4. Maurice Termeer

    Attila Feher Guest

    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/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.

    --
    Attila aka WW
    Attila Feher, Oct 6, 2004
    #4
  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" <> wrote in message
    news:ck07me$5ua$...
    > 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
    Patrick Kowalzick, Oct 6, 2004
    #5
  6. Maurice Termeer

    Rolf Magnus Guest

    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/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.
    Rolf Magnus, Oct 6, 2004
    #6
  7. Maurice Termeer

    Tom Widmer Guest

    On Wed, 06 Oct 2004 11:44:32 +0200, Maurice Termeer
    <> 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
    Tom Widmer, Oct 6, 2004
    #7
  8. Maurice Termeer

    Attila Feher Guest

    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
    Attila Feher, Oct 6, 2004
    #8
  9. > 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
    =?ISO-8859-1?Q?Tobias_G=FCntner?=, Oct 6, 2004
    #9
  10. 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);
    }
    =?ISO-8859-1?Q?=22Nils_O=2E_Sel=E5sdal=22?=, Oct 6, 2004
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John Harrison

    Re: RTTI

    John Harrison, Jul 14, 2003, in forum: C++
    Replies:
    2
    Views:
    445
    John Harrison
    Jul 14, 2003
  2. Alf P. Steinbach

    Re: RTTI

    Alf P. Steinbach, Jul 14, 2003, in forum: C++
    Replies:
    0
    Views:
    458
    Alf P. Steinbach
    Jul 14, 2003
  3. Steven Lien

    About RTTI

    Steven Lien, Aug 19, 2003, in forum: C++
    Replies:
    4
    Views:
    587
    Ivan Vecerina
    Aug 19, 2003
  4. BillyO
    Replies:
    2
    Views:
    481
    dslater
    Sep 30, 2003
  5. tirath
    Replies:
    3
    Views:
    698
    Ivan Vecerina
    Oct 12, 2003
Loading...

Share This Page