alternative to RTTI needed

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Maurice Termeer

    #1

    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_ca st<circle>(p));

    else if (typeid(p) == typeid(triangle ))
    draw(dynamic_ca st<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
  • Attila Feher

    #2
    Re: alternative to RTTI needed

    Maurice Termeer wrote:[color=blue]
    > 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?[/color]
    [SNIP]

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

    Dr.Bob's C++Builder Gate contains programming (technical) information for Borland C++ and C++Builder programmers.


    --
    Attila aka WW


    Comment

    • Maurice Termeer

      #3
      Re: alternative to RTTI needed

      Attila Feher wrote:[color=blue]
      > Maurice Termeer wrote:
      >[color=green]
      >>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
      >>datastructu re 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?[/color]
      >
      > [SNIP]
      >
      > As far as I can tell, you are looking for the Visitor pattern.
      >
      > http://www.drbob42.com/cbuilder/patterns.htm
      >[/color]

      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_ca st<typeid(p)>(p ));
      }

      but c++ won't let me.

      Comment

      • Attila Feher

        #4
        Re: alternative to RTTI needed

        Maurice Termeer wrote:[color=blue]
        > Attila Feher wrote:[/color]
        [SNIP][color=blue][color=green]
        >> As far as I can tell, you are looking for the Visitor pattern.
        >>
        >> http://www.drbob42.com/cbuilder/patterns.htm
        >>[/color]
        >
        > 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_ca st<typeid(p)>(p ));
        > }
        >
        > but c++ won't let me.[/color]

        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=glanc e&s=books&n=507 846

        or

        http://tinyurl.com/43r5l

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

        --
        Attila aka WW


        Comment

        • Rolf Magnus

          #5
          Re: alternative to RTTI needed

          Attila Feher wrote:
          [color=blue]
          > Maurice Termeer wrote:[color=green]
          >> Attila Feher wrote:[/color]
          > [SNIP][color=green][color=darkred]
          >>> As far as I can tell, you are looking for the Visitor pattern.
          >>>
          >>> http://www.drbob42.com/cbuilder/patterns.htm
          >>>[/color]
          >>
          >> 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_ca st<typeid(p)>(p ));
          >> }
          >>
          >> but c++ won't let me.[/color]
          >
          > 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:
          >
          >[/color]
          http://www.amazon.com/exec/obidos/tg...097059720/sr=8[color=blue]
          > -2/ref=pd_csp_2/103-0081174-9277466?v=glanc e&s=books&n=507 846
          >
          > or
          >
          > http://tinyurl.com/43r5l
          >
          > A Design Pattern is (per definition) the opposite to a hack.[/color]

          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.



          Comment

          • Patrick Kowalzick

            #6
            Re: alternative to RTTI needed

            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.a.termeer@st udent.tue.nl> wrote in message
            news:ck07me$5ua $1@news.tue.nl. ..[color=blue]
            > 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[/color]
            like?[color=blue]
            >
            > Right now I have something like:
            >
            > class ShapeDrawer {
            > void draw(shape *p) {
            > if (typeid(p) == typeid(circle))
            > draw(dynamic_ca st<circle>(p));
            >
            > else if (typeid(p) == typeid(triangle ))
            > draw(dynamic_ca st<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[/color]


            Comment

            • Tom Widmer

              #7
              Re: alternative to RTTI needed

              On Wed, 06 Oct 2004 11:44:32 +0200, Maurice Termeer
              <m.a.termeer@st udent.tue.nl> wrote:
              [color=blue]
              >Attila Feher wrote:[color=green]
              >> Maurice Termeer wrote:
              >>[color=darkred]
              >>>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
              >>>inheritanc e tree.
              >>>
              >>>Now suppose I want to write a different component to draw these
              >>>shapes.
              >>>By different component I really mean different, so the whole
              >>>datastructur e 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?[/color]
              >>
              >> [SNIP]
              >>
              >> As far as I can tell, you are looking for the Visitor pattern.
              >>
              >> http://www.drbob42.com/cbuilder/patterns.htm
              >>[/color]
              >
              >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_ca st<typeid(p)>(p ));
              >}
              >
              >but c++ won't let me.[/color]

              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

              Comment

              • Attila Feher

                #8
                Re: alternative to RTTI needed

                Rolf Magnus wrote:
                [SNIP][color=blue][color=green]
                >> http://tinyurl.com/43r5l
                >>
                >> A Design Pattern is (per definition) the opposite to a hack.[/color]
                >
                > 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.[/color]

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



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

                --
                Attila aka WW


                Comment

                • Tobias Güntner

                  #9
                  Re: alternative to RTTI needed

                  > Of[color=blue]
                  > 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.[/color]

                  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<co nst 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

                  Comment

                  • Nils O. Selåsdal

                    #10
                    Re: alternative to RTTI needed

                    Maurice Termeer wrote:[color=blue]
                    > 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_ca st<circle>(p));
                    >
                    > else if (typeid(p) == typeid(triangle ))
                    > draw(dynamic_ca st<triangle>(p) );
                    >
                    > else ...
                    > }
                    >
                    > void draw(circle *p) { ... }
                    > void draw(triangle *p) { ... }
                    > }[/color]
                    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);
                    }

                    Comment

                    Working...