Help a poor FORTRAN programmer with member functions?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Anthony Jones

    Help a poor FORTRAN programmer with member functions?


    Just a bit of background: I'm one of a group of FORTRAN programmers, looking
    to switch to C++. We are trying to write a few simple examples to
    demonstrate the power of the language to our manager, so he will send us all
    on a conversion course.

    One of many reasons is that our code is littered with examples of:

    SUBROUTINE PRINT_ITEM(ITEM , ITEM_TYPE)
    IF (ITEM_TYPE .EQ. SQUARE) THEN
    CALL PRINT_SQUARE(IT EM)
    ELSEIF (ITEM_TYPE .EQ. CIRCLE) THEN
    CALL PRINT_CIRCLE(IT EM)
    ELSEIF ...
    (lots more item types)
    ENDIF
    END

    (with apologies for sullying the group with FORTRAN code).

    Obviously We need to find and modify all these blocks whenever we add a new
    object type, or operation.

    I want to write a C++ equivalent, using classes and member functions so that
    I can print (or draw, or interrogate, or whatever...) an object without
    knowing its type at runtime.

    The latest of several attempts is shown below - the compiler complains about
    the void* in the PrintObject function, though I thought I'd read that void*
    could be used to mean "pointer to something, but I don't know what".

    Can this code be modifed to get the effect I want? I'd like to avoid using
    pointers to functions if possible.

    Thanks!


    #include <iostream.h>

    // Class declarations
    // ------------------

    class Square{
    public:
    void Print();
    };

    void Square::Print() {
    cout << "This is a square";
    }

    class Circle{
    public:
    void Print();
    };

    void Circle::Print() {
    cout << "This is a circle";
    }

    // Print object function
    // ---------------------

    void PrintObject(voi d* object){
    object->Print();
    }

    // Main Program
    // ------------

    int main(){
    Square* square;
    Circle* circle;

    square = new Square;
    circle = new Circle;

    // Call member functions directly

    circle->Print();
    square->Print();

    // Call member functions through PrintObject function

    PrintObject(cir cle);
    PrintObject(squ are);

    return 0;

    }



  • Howard

    #2
    Re: Help a poor FORTRAN programmer with member functions?


    "Anthony Jones" <me@privacy.net > wrote in message
    news:3K-dnX2X98CFAujdRV n-uQ@nildram.net. ..[color=blue]
    > I want to write a C++ equivalent, using classes and member functions so[/color]
    that[color=blue]
    > I can print (or draw, or interrogate, or whatever...) an object without
    > knowing its type at runtime.[/color]

    You mean without knowing its type "at compile time"? It has to be known at
    run-time, or you'd never be able to do *anything* with it! :-)
    [color=blue]
    >
    > The latest of several attempts is shown below - the compiler complains[/color]
    about[color=blue]
    > the void* in the PrintObject function, though I thought I'd read that[/color]
    void*[color=blue]
    > could be used to mean "pointer to something, but I don't know what".
    >[/color]

    Yes, you can use a void* to store any other pointer, but you can never *use*
    that pointer for anything (dereference it) unless you first cast it back to
    whatever it's supposed to be.
    [color=blue]
    >
    > // Print object function
    > // ---------------------
    >
    > void PrintObject(voi d* object){
    > object->Print();
    > }
    >[/color]

    What you want to do instead of using a void* is to have a base class from
    which all your specific shapes inherit. Then you make a virtual Print
    function in the base class, and have each derived class overried that
    function to do its own version of printing.

    You really need to do some reading up on base classes, inheritance, and
    virtual functions before attempting to go further on this.

    -Howard






    Comment

    • Howard

      #3
      Re: Help a poor FORTRAN programmer with member functions?


      "Anthony Jones" <me@privacy.net > wrote in message
      news:3K-dnX2X98CFAujdRV n-uQ@nildram.net. ..[color=blue]
      > I want to write a C++ equivalent, using classes and member functions so[/color]
      that[color=blue]
      > I can print (or draw, or interrogate, or whatever...) an object without
      > knowing its type at runtime.[/color]

      You mean without knowing its type "at compile time"? It has to be known at
      run-time, or you'd never be able to do *anything* with it! :-)
      [color=blue]
      >
      > The latest of several attempts is shown below - the compiler complains[/color]
      about[color=blue]
      > the void* in the PrintObject function, though I thought I'd read that[/color]
      void*[color=blue]
      > could be used to mean "pointer to something, but I don't know what".
      >[/color]

      Yes, you can use a void* to store any other pointer, but you can never *use*
      that pointer for anything (dereference it) unless you first cast it back to
      whatever it's supposed to be.
      [color=blue]
      >
      > // Print object function
      > // ---------------------
      >
      > void PrintObject(voi d* object){
      > object->Print();
      > }
      >[/color]

      What you want to do instead of using a void* is to have a base class from
      which all your specific shapes inherit. Then you make a virtual Print
      function in the base class, and have each derived class overried that
      function to do its own version of printing.

      You really need to do some reading up on base classes, inheritance, and
      virtual functions before attempting to go further on this.

      -Howard






      Comment

      • Benoit Mathieu

        #4
        Re: Help a poor FORTRAN programmer with member functions?

        [color=blue]
        > What you want to do instead of using a void* is to have a base class from
        > which all your specific shapes inherit. Then you make a virtual Print
        > function in the base class, and have each derived class overried that
        > function to do its own version of printing.
        >
        > You really need to do some reading up on base classes, inheritance, and
        > virtual functions before attempting to go further on this.[/color]

        I also suggest that you have a look at some examples
        available on the internet.
        google for "c++ polymorphism example" ... you might find
        some examples with circles and rectangles...

        See for example http://onestepback.org/articles/poly/

        Comment

        • Benoit Mathieu

          #5
          Re: Help a poor FORTRAN programmer with member functions?

          [color=blue]
          > What you want to do instead of using a void* is to have a base class from
          > which all your specific shapes inherit. Then you make a virtual Print
          > function in the base class, and have each derived class overried that
          > function to do its own version of printing.
          >
          > You really need to do some reading up on base classes, inheritance, and
          > virtual functions before attempting to go further on this.[/color]

          I also suggest that you have a look at some examples
          available on the internet.
          google for "c++ polymorphism example" ... you might find
          some examples with circles and rectangles...

          See for example http://onestepback.org/articles/poly/

          Comment

          • John Harrison

            #6
            Re: Help a poor FORTRAN programmer with member functions?


            "Anthony Jones" <me@privacy.net > wrote in message
            news:3K-dnX2X98CFAujdRV n-uQ@nildram.net. ..[color=blue]
            >
            > Just a bit of background: I'm one of a group of FORTRAN programmers,[/color]
            looking[color=blue]
            > to switch to C++. We are trying to write a few simple examples to
            > demonstrate the power of the language to our manager, so he will send us[/color]
            all[color=blue]
            > on a conversion course.
            >
            > One of many reasons is that our code is littered with examples of:
            >
            > SUBROUTINE PRINT_ITEM(ITEM , ITEM_TYPE)
            > IF (ITEM_TYPE .EQ. SQUARE) THEN
            > CALL PRINT_SQUARE(IT EM)
            > ELSEIF (ITEM_TYPE .EQ. CIRCLE) THEN
            > CALL PRINT_CIRCLE(IT EM)
            > ELSEIF ...
            > (lots more item types)
            > ENDIF
            > END
            >
            > (with apologies for sullying the group with FORTRAN code).
            >
            > Obviously We need to find and modify all these blocks whenever we add a[/color]
            new[color=blue]
            > object type, or operation.
            >
            > I want to write a C++ equivalent, using classes and member functions so[/color]
            that[color=blue]
            > I can print (or draw, or interrogate, or whatever...) an object without
            > knowing its type at runtime.
            >[/color]

            For God's sake! VIRTUAL FUNCTIONS

            Look it up in your favourite text book. They do exactly what you need.

            john


            Comment

            • John Harrison

              #7
              Re: Help a poor FORTRAN programmer with member functions?


              "Anthony Jones" <me@privacy.net > wrote in message
              news:3K-dnX2X98CFAujdRV n-uQ@nildram.net. ..[color=blue]
              >
              > Just a bit of background: I'm one of a group of FORTRAN programmers,[/color]
              looking[color=blue]
              > to switch to C++. We are trying to write a few simple examples to
              > demonstrate the power of the language to our manager, so he will send us[/color]
              all[color=blue]
              > on a conversion course.
              >
              > One of many reasons is that our code is littered with examples of:
              >
              > SUBROUTINE PRINT_ITEM(ITEM , ITEM_TYPE)
              > IF (ITEM_TYPE .EQ. SQUARE) THEN
              > CALL PRINT_SQUARE(IT EM)
              > ELSEIF (ITEM_TYPE .EQ. CIRCLE) THEN
              > CALL PRINT_CIRCLE(IT EM)
              > ELSEIF ...
              > (lots more item types)
              > ENDIF
              > END
              >
              > (with apologies for sullying the group with FORTRAN code).
              >
              > Obviously We need to find and modify all these blocks whenever we add a[/color]
              new[color=blue]
              > object type, or operation.
              >
              > I want to write a C++ equivalent, using classes and member functions so[/color]
              that[color=blue]
              > I can print (or draw, or interrogate, or whatever...) an object without
              > knowing its type at runtime.
              >[/color]

              For God's sake! VIRTUAL FUNCTIONS

              Look it up in your favourite text book. They do exactly what you need.

              john


              Comment

              • Kevin Goodsell

                #8
                Re: Help a poor FORTRAN programmer with member functions?

                Anthony Jones wrote:
                [color=blue]
                > Just a bit of background: I'm one of a group of FORTRAN programmers, looking
                > to switch to C++. We are trying to write a few simple examples to
                > demonstrate the power of the language to our manager, so he will send us all
                > on a conversion course.
                >
                > One of many reasons is that our code is littered with examples of:
                >
                > SUBROUTINE PRINT_ITEM(ITEM , ITEM_TYPE)
                > IF (ITEM_TYPE .EQ. SQUARE) THEN
                > CALL PRINT_SQUARE(IT EM)
                > ELSEIF (ITEM_TYPE .EQ. CIRCLE) THEN
                > CALL PRINT_CIRCLE(IT EM)
                > ELSEIF ...
                > (lots more item types)
                > ENDIF
                > END[/color]

                Yikes.
                [color=blue]
                >
                > (with apologies for sullying the group with FORTRAN code).
                >
                > Obviously We need to find and modify all these blocks whenever we add a new
                > object type, or operation.
                >
                > I want to write a C++ equivalent, using classes and member functions so that
                > I can print (or draw, or interrogate, or whatever...) an object without
                > knowing its type at runtime.
                >
                > The latest of several attempts is shown below - the compiler complains about
                > the void* in the PrintObject function, though I thought I'd read that void*
                > could be used to mean "pointer to something, but I don't know what".[/color]

                Yes, and it also means "no type safety". void* should be avoided, and is
                certainly not the right way to accomplish polymorphic behavior (which is
                what you are looking for, whether you know that or not).
                [color=blue]
                >
                > Can this code be modifed to get the effect I want? I'd like to avoid using
                > pointers to functions if possible.
                >
                > Thanks!
                >
                >
                > #include <iostream.h>[/color]

                I realize you are new to this, so please understand that I'll point out
                any and all errors I spot in your code, regardless of whether they are
                relevant to the immediate question. Also, my definition of an 'error'
                includes anything that is not defined by the C++ standard, anything that
                may behave unexpectedly, or that may behave differently on different
                implementations (even if one of the "different implementations " is a
                hypothetical implementation that does not actually exist). This is
                standard practice for many of the people in this group.

                That said, <iostream.h> is not part of the C++ standard. It is old,
                pre-standard C++. Standard C++ uses <iostream> (with no .h).
                [color=blue]
                >
                > // Class declarations
                > // ------------------
                >
                > class Square{
                > public:
                > void Print();
                > };[/color]

                In order to achieve polymorphic behavior, you need a few things that you
                are missing: Inheritance, and virtual functions. Your example involves
                shapes. Great, so create a class representing a shape. It will serve as
                the base class for you other shapes.

                class Shape
                {
                public:
                virtual void Print() = 0;
                };

                class Square : public Shape
                {
                public:
                void Print();
                };

                class Circle : public Shape
                {
                public:
                void Print();
                };

                The "class Square : public Shape" part can be read as "Square IS A
                Shape". This is often referred to as the 'is-a' relationship. Squares
                and Circles are both types of Shapes, and thus share some of the same
                functionality -- in particular, they all have the ability to perform the
                'Print' operation.

                The 'virtual' qualifier on Shape::Print() just means "this function can
                behave differently in different base classes". This allows Square and
                Circle to give their own version of Print() that does what they need it
                to do. The '= 0' part is a bit more confusing. It has basically 2
                effects: 1) It allows Shape to decline to implement Print(). There's no
                reasonable way to print a generic shape, so this makes sense. It
                essentially requires base classes to provide Print() instead (though a
                base class can pull the same trick, passing the burden of implementing
                the function onto /its/ base classes). 2) It makes Shape an abstract
                class, which is a class that can really only be used as a base class.
                You can't create an object of type Shape, because Shape is not a
                complete class.
                [color=blue]
                >
                > void Square::Print() {
                > cout << "This is a square";[/color]

                In modern C++, 'cout' (along with most standard library names) resides
                in namespace std. This means that the fully qualified name is std::cout.
                You can use this fully-qualified name, or you can put a line like this:

                using namespace std;

                at the top of your source files, just after the #include directives.
                This is sort of the lazy way of doing it, and can be bad in some cases,
                but it's the easiest way to get started. There are other options as
                well, but you'll learn about that later.

                Other than that, no changes are required here.
                [color=blue]
                > }
                >
                > class Circle{
                > public:
                > void Print();
                > };
                >
                > void Circle::Print() {
                > cout << "This is a circle";[/color]

                Same comments as for Square::Print() .
                [color=blue]
                > }
                >
                > // Print object function
                > // ---------------------
                >
                > void PrintObject(voi d* object){[/color]

                Now, you don't want to use void* here. What you want is a function to
                print an object. More specifically, a Shape. So try this instead:

                void PrintShape(Shap e *shape)
                {
                [color=blue]
                > object->Print();[/color]

                shape->Print();
                [color=blue]
                > }
                >
                > // Main Program
                > // ------------
                >
                > int main(){
                > Square* square;
                > Circle* circle;
                >
                > square = new Square;
                > circle = new Circle;[/color]

                Generally, you shouldn't use 'new' unless you absolutely have to. It
                tends to be used in real programs that do what you are demonstrating, so
                its use here isn't completely inappropriate, but normally when you want
                a Square you should just say

                Square my_square;

                It's also worth noting that a more typical way of doing what you are
                doing would be like this:

                Shape *square;
                Shape *circle;

                square = new Square;
                circle = new Circle;

                In fact, you'd probably be most likely to have a collection of Shape
                pointers (in an array, or a container class). Such collections generally
                have to be homogeneous, so they can't contain Square pointers and Circle
                pointers. Luckily they don't need to, because Shape pointers can point
                to Squares, Circles, and any other type that IS A Shape.
                [color=blue]
                >
                > // Call member functions directly
                >
                > circle->Print();
                > square->Print();
                >
                > // Call member functions through PrintObject function
                >
                > PrintObject(cir cle);
                > PrintObject(squ are);[/color]

                Replace these with the new name 'PrintShape' and you're all set.
                [color=blue]
                >
                > return 0;
                >
                > }
                >[/color]

                -Kevin
                --
                My email address is valid, but changes periodically.
                To contact me please use the address from a recent posting.

                Comment

                • Kevin Goodsell

                  #9
                  Re: Help a poor FORTRAN programmer with member functions?

                  Anthony Jones wrote:
                  [color=blue]
                  > Just a bit of background: I'm one of a group of FORTRAN programmers, looking
                  > to switch to C++. We are trying to write a few simple examples to
                  > demonstrate the power of the language to our manager, so he will send us all
                  > on a conversion course.
                  >
                  > One of many reasons is that our code is littered with examples of:
                  >
                  > SUBROUTINE PRINT_ITEM(ITEM , ITEM_TYPE)
                  > IF (ITEM_TYPE .EQ. SQUARE) THEN
                  > CALL PRINT_SQUARE(IT EM)
                  > ELSEIF (ITEM_TYPE .EQ. CIRCLE) THEN
                  > CALL PRINT_CIRCLE(IT EM)
                  > ELSEIF ...
                  > (lots more item types)
                  > ENDIF
                  > END[/color]

                  Yikes.
                  [color=blue]
                  >
                  > (with apologies for sullying the group with FORTRAN code).
                  >
                  > Obviously We need to find and modify all these blocks whenever we add a new
                  > object type, or operation.
                  >
                  > I want to write a C++ equivalent, using classes and member functions so that
                  > I can print (or draw, or interrogate, or whatever...) an object without
                  > knowing its type at runtime.
                  >
                  > The latest of several attempts is shown below - the compiler complains about
                  > the void* in the PrintObject function, though I thought I'd read that void*
                  > could be used to mean "pointer to something, but I don't know what".[/color]

                  Yes, and it also means "no type safety". void* should be avoided, and is
                  certainly not the right way to accomplish polymorphic behavior (which is
                  what you are looking for, whether you know that or not).
                  [color=blue]
                  >
                  > Can this code be modifed to get the effect I want? I'd like to avoid using
                  > pointers to functions if possible.
                  >
                  > Thanks!
                  >
                  >
                  > #include <iostream.h>[/color]

                  I realize you are new to this, so please understand that I'll point out
                  any and all errors I spot in your code, regardless of whether they are
                  relevant to the immediate question. Also, my definition of an 'error'
                  includes anything that is not defined by the C++ standard, anything that
                  may behave unexpectedly, or that may behave differently on different
                  implementations (even if one of the "different implementations " is a
                  hypothetical implementation that does not actually exist). This is
                  standard practice for many of the people in this group.

                  That said, <iostream.h> is not part of the C++ standard. It is old,
                  pre-standard C++. Standard C++ uses <iostream> (with no .h).
                  [color=blue]
                  >
                  > // Class declarations
                  > // ------------------
                  >
                  > class Square{
                  > public:
                  > void Print();
                  > };[/color]

                  In order to achieve polymorphic behavior, you need a few things that you
                  are missing: Inheritance, and virtual functions. Your example involves
                  shapes. Great, so create a class representing a shape. It will serve as
                  the base class for you other shapes.

                  class Shape
                  {
                  public:
                  virtual void Print() = 0;
                  };

                  class Square : public Shape
                  {
                  public:
                  void Print();
                  };

                  class Circle : public Shape
                  {
                  public:
                  void Print();
                  };

                  The "class Square : public Shape" part can be read as "Square IS A
                  Shape". This is often referred to as the 'is-a' relationship. Squares
                  and Circles are both types of Shapes, and thus share some of the same
                  functionality -- in particular, they all have the ability to perform the
                  'Print' operation.

                  The 'virtual' qualifier on Shape::Print() just means "this function can
                  behave differently in different base classes". This allows Square and
                  Circle to give their own version of Print() that does what they need it
                  to do. The '= 0' part is a bit more confusing. It has basically 2
                  effects: 1) It allows Shape to decline to implement Print(). There's no
                  reasonable way to print a generic shape, so this makes sense. It
                  essentially requires base classes to provide Print() instead (though a
                  base class can pull the same trick, passing the burden of implementing
                  the function onto /its/ base classes). 2) It makes Shape an abstract
                  class, which is a class that can really only be used as a base class.
                  You can't create an object of type Shape, because Shape is not a
                  complete class.
                  [color=blue]
                  >
                  > void Square::Print() {
                  > cout << "This is a square";[/color]

                  In modern C++, 'cout' (along with most standard library names) resides
                  in namespace std. This means that the fully qualified name is std::cout.
                  You can use this fully-qualified name, or you can put a line like this:

                  using namespace std;

                  at the top of your source files, just after the #include directives.
                  This is sort of the lazy way of doing it, and can be bad in some cases,
                  but it's the easiest way to get started. There are other options as
                  well, but you'll learn about that later.

                  Other than that, no changes are required here.
                  [color=blue]
                  > }
                  >
                  > class Circle{
                  > public:
                  > void Print();
                  > };
                  >
                  > void Circle::Print() {
                  > cout << "This is a circle";[/color]

                  Same comments as for Square::Print() .
                  [color=blue]
                  > }
                  >
                  > // Print object function
                  > // ---------------------
                  >
                  > void PrintObject(voi d* object){[/color]

                  Now, you don't want to use void* here. What you want is a function to
                  print an object. More specifically, a Shape. So try this instead:

                  void PrintShape(Shap e *shape)
                  {
                  [color=blue]
                  > object->Print();[/color]

                  shape->Print();
                  [color=blue]
                  > }
                  >
                  > // Main Program
                  > // ------------
                  >
                  > int main(){
                  > Square* square;
                  > Circle* circle;
                  >
                  > square = new Square;
                  > circle = new Circle;[/color]

                  Generally, you shouldn't use 'new' unless you absolutely have to. It
                  tends to be used in real programs that do what you are demonstrating, so
                  its use here isn't completely inappropriate, but normally when you want
                  a Square you should just say

                  Square my_square;

                  It's also worth noting that a more typical way of doing what you are
                  doing would be like this:

                  Shape *square;
                  Shape *circle;

                  square = new Square;
                  circle = new Circle;

                  In fact, you'd probably be most likely to have a collection of Shape
                  pointers (in an array, or a container class). Such collections generally
                  have to be homogeneous, so they can't contain Square pointers and Circle
                  pointers. Luckily they don't need to, because Shape pointers can point
                  to Squares, Circles, and any other type that IS A Shape.
                  [color=blue]
                  >
                  > // Call member functions directly
                  >
                  > circle->Print();
                  > square->Print();
                  >
                  > // Call member functions through PrintObject function
                  >
                  > PrintObject(cir cle);
                  > PrintObject(squ are);[/color]

                  Replace these with the new name 'PrintShape' and you're all set.
                  [color=blue]
                  >
                  > return 0;
                  >
                  > }
                  >[/color]

                  -Kevin
                  --
                  My email address is valid, but changes periodically.
                  To contact me please use the address from a recent posting.

                  Comment

                  • David Harmon

                    #10
                    Re: Help a poor FORTRAN programmer with member functions?

                    On Thu, 8 Apr 2004 19:51:23 +0100 in comp.lang.c++, "Anthony Jones"
                    <me@privacy.net > wrote,[color=blue]
                    >I want to write a C++ equivalent, using classes and member functions so that
                    >I can print (or draw, or interrogate, or whatever...) an object without
                    >knowing its type at runtime.[/color]

                    This issue is covered in Marshall Cline's C++ FAQ. See the topic
                    "[20.4] I have a heterogeneous list of objects, and my code needs to do
                    class-specific things to the objects. Seems like this ought to use
                    dynamic binding but can't figure it out. What should I do?" It is
                    always good to check the FAQ before posting. You can get the FAQ at:


                    Comment

                    • David Harmon

                      #11
                      Re: Help a poor FORTRAN programmer with member functions?

                      On Thu, 8 Apr 2004 19:51:23 +0100 in comp.lang.c++, "Anthony Jones"
                      <me@privacy.net > wrote,[color=blue]
                      >I want to write a C++ equivalent, using classes and member functions so that
                      >I can print (or draw, or interrogate, or whatever...) an object without
                      >knowing its type at runtime.[/color]

                      This issue is covered in Marshall Cline's C++ FAQ. See the topic
                      "[20.4] I have a heterogeneous list of objects, and my code needs to do
                      class-specific things to the objects. Seems like this ought to use
                      dynamic binding but can't figure it out. What should I do?" It is
                      always good to check the FAQ before posting. You can get the FAQ at:


                      Comment

                      • Jeff Flinn

                        #12
                        Re: Help a poor FORTRAN programmer with member functions?

                        Anthony,

                        See the few additions/modifications in your code below. You are very close
                        but only missing a few items. You need to use virtual member functions
                        rather than simple member functions. Which means you need to derive from an
                        base class that declares a virtual member function.

                        "Anthony Jones" <me@privacy.net > wrote in message
                        news:3K-dnX2X98CFAujdRV n-uQ@nildram.net. ..[color=blue]
                        >
                        > Just a bit of background: I'm one of a group of FORTRAN programmers,[/color]
                        looking[color=blue]
                        > to switch to C++. We are trying to write a few simple examples to
                        > demonstrate the power of the language to our manager, so he will send us[/color]
                        all[color=blue]
                        > on a conversion course.
                        >
                        > One of many reasons is that our code is littered with examples of:
                        >
                        > SUBROUTINE PRINT_ITEM(ITEM , ITEM_TYPE)
                        > IF (ITEM_TYPE .EQ. SQUARE) THEN
                        > CALL PRINT_SQUARE(IT EM)
                        > ELSEIF (ITEM_TYPE .EQ. CIRCLE) THEN
                        > CALL PRINT_CIRCLE(IT EM)
                        > ELSEIF ...
                        > (lots more item types)
                        > ENDIF
                        > END
                        >
                        > (with apologies for sullying the group with FORTRAN code).
                        >
                        > Obviously We need to find and modify all these blocks whenever we add a[/color]
                        new[color=blue]
                        > object type, or operation.
                        >
                        > I want to write a C++ equivalent, using classes and member functions so[/color]
                        that[color=blue]
                        > I can print (or draw, or interrogate, or whatever...) an object without
                        > knowing its type at runtime.
                        >
                        > The latest of several attempts is shown below - the compiler complains[/color]
                        about[color=blue]
                        > the void* in the PrintObject function, though I thought I'd read that[/color]
                        void*[color=blue]
                        > could be used to mean "pointer to something, but I don't know what".
                        >
                        > Can this code be modifed to get the effect I want? I'd like to avoid using
                        > pointers to functions if possible.
                        >
                        > Thanks!
                        >
                        >
                        > #include <iostream.h>
                        >
                        > // Class declarations
                        > // ------------------[/color]

                        class Geometry
                        {
                        public:
                        virtual ~Geometry(){} // need a virtual destructor in this case

                        virtual void Print(){}
                        };
                        [color=blue]
                        >
                        > class Square{[/color]

                        replace with:

                        class Square : public Geometry{

                        [color=blue]
                        > public:
                        > void Print();
                        > };
                        >
                        > void Square::Print() {
                        > cout << "This is a square";
                        > }
                        >
                        > class Circle{[/color]

                        replace with:

                        class Circle : public Geometry{
                        [color=blue]
                        > public:
                        > void Print();
                        > };
                        >
                        > void Circle::Print() {
                        > cout << "This is a circle";
                        > }
                        >
                        > // Print object function
                        > // ---------------------
                        >
                        > void PrintObject(voi d* object){
                        > object->Print();
                        > }[/color]

                        replace with:

                        void PrintObject( Geometry* aObjectPtr )
                        {
                        aObjectPtr->Print();
                        }

                        or better yet:

                        void PrintObject( Geometry& aObject ) // by reference
                        {
                        aObject.Print() ;
                        }
                        [color=blue]
                        >
                        > // Main Program
                        > // ------------
                        >
                        > int main(){
                        > Square* square;
                        > Circle* circle;
                        >
                        > square = new Square;
                        > circle = new Circle;
                        >
                        > // Call member functions directly
                        >
                        > circle->Print();
                        > square->Print();
                        >
                        > // Call member functions through PrintObject function
                        >
                        > PrintObject(cir cle);
                        > PrintObject(squ are);[/color]

                        to use the reference version replace with:

                        PrintObject( *circle ); // dereference the pointers to get references
                        PrintObject( *square );
                        [color=blue]
                        >
                        > return 0;
                        >
                        > }[/color]

                        Better yet is to forego dealing with pointers altogether.

                        int main()
                        {
                        Square lSquare;
                        Circle lCircle;

                        lCircle.Print() ;
                        lSquare.Print() ;

                        PrintObject( lSquare );
                        PrintObject( lCircle );

                        return 0;
                        }

                        Additionally, since typically a Print function would not modify the state of
                        it's object, it's best to declare the member function as 'const'. As in:

                        class Geometry
                        {
                        public:
                        virtual ~Geometry(){}
                        virtual void Print()const{}
                        };

                        And finally to show the real power:

                        #include <vector>

                        int main()
                        {
                        typedef std::vector<Geo metry*> ;

                        tGeoPtrs lGeoPtrs;

                        lGeoPtrs.push_b ack( new Circle );
                        lGeoPtrs.push_b ack( new Square );
                        lGeoPtrs.push_b ack( new Circle );
                        lGeoPtrs.push_b ack( new Square );
                        lGeoPtrs.push_b ack( new Circle );

                        for( tGeoPtrs::itera tor lItr = lGeoPtrs.begin( ) ; lItr != lGeoPtrs.end()
                        ; ++lItr )
                        {
                        (*lItr)->Print();

                        // or

                        PrintObject( *lItr ); // Pointer overload

                        // or

                        PrintObject( **lItr ); // reference overload

                        delete *lItr; // delete it when we're done

                        *lItr = NULL;
                        }

                        return 0;
                        }

                        This is just the beginning of the power/expressivenes advantages of C++
                        versus Fortran.

                        Jeff F




                        Comment

                        • Jeff Flinn

                          #13
                          Re: Help a poor FORTRAN programmer with member functions?

                          Anthony,

                          See the few additions/modifications in your code below. You are very close
                          but only missing a few items. You need to use virtual member functions
                          rather than simple member functions. Which means you need to derive from an
                          base class that declares a virtual member function.

                          "Anthony Jones" <me@privacy.net > wrote in message
                          news:3K-dnX2X98CFAujdRV n-uQ@nildram.net. ..[color=blue]
                          >
                          > Just a bit of background: I'm one of a group of FORTRAN programmers,[/color]
                          looking[color=blue]
                          > to switch to C++. We are trying to write a few simple examples to
                          > demonstrate the power of the language to our manager, so he will send us[/color]
                          all[color=blue]
                          > on a conversion course.
                          >
                          > One of many reasons is that our code is littered with examples of:
                          >
                          > SUBROUTINE PRINT_ITEM(ITEM , ITEM_TYPE)
                          > IF (ITEM_TYPE .EQ. SQUARE) THEN
                          > CALL PRINT_SQUARE(IT EM)
                          > ELSEIF (ITEM_TYPE .EQ. CIRCLE) THEN
                          > CALL PRINT_CIRCLE(IT EM)
                          > ELSEIF ...
                          > (lots more item types)
                          > ENDIF
                          > END
                          >
                          > (with apologies for sullying the group with FORTRAN code).
                          >
                          > Obviously We need to find and modify all these blocks whenever we add a[/color]
                          new[color=blue]
                          > object type, or operation.
                          >
                          > I want to write a C++ equivalent, using classes and member functions so[/color]
                          that[color=blue]
                          > I can print (or draw, or interrogate, or whatever...) an object without
                          > knowing its type at runtime.
                          >
                          > The latest of several attempts is shown below - the compiler complains[/color]
                          about[color=blue]
                          > the void* in the PrintObject function, though I thought I'd read that[/color]
                          void*[color=blue]
                          > could be used to mean "pointer to something, but I don't know what".
                          >
                          > Can this code be modifed to get the effect I want? I'd like to avoid using
                          > pointers to functions if possible.
                          >
                          > Thanks!
                          >
                          >
                          > #include <iostream.h>
                          >
                          > // Class declarations
                          > // ------------------[/color]

                          class Geometry
                          {
                          public:
                          virtual ~Geometry(){} // need a virtual destructor in this case

                          virtual void Print(){}
                          };
                          [color=blue]
                          >
                          > class Square{[/color]

                          replace with:

                          class Square : public Geometry{

                          [color=blue]
                          > public:
                          > void Print();
                          > };
                          >
                          > void Square::Print() {
                          > cout << "This is a square";
                          > }
                          >
                          > class Circle{[/color]

                          replace with:

                          class Circle : public Geometry{
                          [color=blue]
                          > public:
                          > void Print();
                          > };
                          >
                          > void Circle::Print() {
                          > cout << "This is a circle";
                          > }
                          >
                          > // Print object function
                          > // ---------------------
                          >
                          > void PrintObject(voi d* object){
                          > object->Print();
                          > }[/color]

                          replace with:

                          void PrintObject( Geometry* aObjectPtr )
                          {
                          aObjectPtr->Print();
                          }

                          or better yet:

                          void PrintObject( Geometry& aObject ) // by reference
                          {
                          aObject.Print() ;
                          }
                          [color=blue]
                          >
                          > // Main Program
                          > // ------------
                          >
                          > int main(){
                          > Square* square;
                          > Circle* circle;
                          >
                          > square = new Square;
                          > circle = new Circle;
                          >
                          > // Call member functions directly
                          >
                          > circle->Print();
                          > square->Print();
                          >
                          > // Call member functions through PrintObject function
                          >
                          > PrintObject(cir cle);
                          > PrintObject(squ are);[/color]

                          to use the reference version replace with:

                          PrintObject( *circle ); // dereference the pointers to get references
                          PrintObject( *square );
                          [color=blue]
                          >
                          > return 0;
                          >
                          > }[/color]

                          Better yet is to forego dealing with pointers altogether.

                          int main()
                          {
                          Square lSquare;
                          Circle lCircle;

                          lCircle.Print() ;
                          lSquare.Print() ;

                          PrintObject( lSquare );
                          PrintObject( lCircle );

                          return 0;
                          }

                          Additionally, since typically a Print function would not modify the state of
                          it's object, it's best to declare the member function as 'const'. As in:

                          class Geometry
                          {
                          public:
                          virtual ~Geometry(){}
                          virtual void Print()const{}
                          };

                          And finally to show the real power:

                          #include <vector>

                          int main()
                          {
                          typedef std::vector<Geo metry*> ;

                          tGeoPtrs lGeoPtrs;

                          lGeoPtrs.push_b ack( new Circle );
                          lGeoPtrs.push_b ack( new Square );
                          lGeoPtrs.push_b ack( new Circle );
                          lGeoPtrs.push_b ack( new Square );
                          lGeoPtrs.push_b ack( new Circle );

                          for( tGeoPtrs::itera tor lItr = lGeoPtrs.begin( ) ; lItr != lGeoPtrs.end()
                          ; ++lItr )
                          {
                          (*lItr)->Print();

                          // or

                          PrintObject( *lItr ); // Pointer overload

                          // or

                          PrintObject( **lItr ); // reference overload

                          delete *lItr; // delete it when we're done

                          *lItr = NULL;
                          }

                          return 0;
                          }

                          This is just the beginning of the power/expressivenes advantages of C++
                          versus Fortran.

                          Jeff F




                          Comment

                          Working...