question about method pointers and subclasses

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Yu Hu

    question about method pointers and subclasses

    Hello,

    Is it legal (and moral) to assign a method pointer with the proper
    prototype to a variable whose type involves the superclass? (Sorry if my
    wording of the question is imprecise, I'm not sure what all the right
    terminology is.) A code example should make it clear what I'm asking:

    class A
    {
    public:
    int Fn1( int x );
    // ...
    };

    typedef int (A::*AMemFn)( int x );

    class B : public A
    {
    public:
    int Fn2( int x );
    // ...
    };

    // Assume the methods are defined and the classes are completed elsewhere

    AMemFn f = &B::Fn2; // Is this OK?

    // Two examples of how I am using f:
    B b_obj;
    int r = (b_obj.*f)( 5 );

    A *a_ptr = new B;
    r = (a->(*f))( 5 );


    In my code, I know that the type of the object and the class that the
    method being stored in the variable agree. It still feels sketchy to me
    because it seems like you could screw yourself by making an object of
    type A and then calling a method of class B on it, which can cause bad
    things to happen.

    Visual C++ and g++ permit me to do this, but I wanted to know if this
    generally should work.


    --
    yph@cs.stanford .edu
  • Andrey Tarasevich

    #2
    Re: question about method pointers and subclasses

    Yu Hu wrote:
    [color=blue]
    > Is it legal (and moral) to assign a method pointer with the proper
    > prototype to a variable whose type involves the superclass? (Sorry if my
    > wording of the question is imprecise, I'm not sure what all the right
    > terminology is.) A code example should make it clear what I'm asking:
    >
    > class A
    > {
    > public:
    > int Fn1( int x );
    > // ...
    > };
    >
    > typedef int (A::*AMemFn)( int x );
    >
    > class B : public A
    > {
    > public:
    > int Fn2( int x );
    > // ...
    > };
    >
    > // Assume the methods are defined and the classes are completed elsewhere
    >
    > AMemFn f = &B::Fn2; // Is this OK?[/color]

    This will not compile. Member pointer types are contravariant, not
    covariant. The following, however, is perfectly legal

    AMemFn f = static_cast<AMe mFn>(&B::Fn2);

    There are obvious dangers in such conversions, so it is up to you to
    decide whether it is OK or not OK to do it in your code.
    [color=blue]
    > // Two examples of how I am using f:
    > B b_obj;
    > int r = (b_obj.*f)( 5 );
    >
    > A *a_ptr = new B;
    > r = (a->(*f))( 5 );[/color]

    In the second case you probably meant

    r = (a_ptr->*f)(5);

    Both calls are fine, provided the 'f' pointer is initialized as shown above.
    [color=blue]
    > In my code, I know that the type of the object and the class that the
    > method being stored in the variable agree. It still feels sketchy to me
    > because it seems like you could screw yourself by making an object of
    > type A and then calling a method of class B on it, which can cause bad
    > things to happen.[/color]

    Yes, that's the danger I was talking about.
    [color=blue]
    > Visual C++ and g++ permit me to do this, but I wanted to know if this
    > generally should work.[/color]

    Yes, it is guaranteed to work by C++ standard.

    --
    Best regards,
    Andrey Tarasevich
    Brainbench C and C++ Programming MVP

    Comment

    • Gianni Mariani

      #3
      Re: question about method pointers and subclasses

      Yu Hu wrote:
      [color=blue]
      > Visual C++ and g++ permit me to do this, but I wanted to know if this
      > generally should work.
      >
      >[/color]

      Funny - after I remove some compiler errors, gcc says:

      aaa.cpp:19: error: cannot convert `int (B::*)(int)' to `int (A::*)(int)' in

      I suspect that you're out of luck. What you tried to do is illegal.

      If you KNOW the object is a b then try this instead.

      class A
      {
      public:
      int Fn1( int x );
      // ...
      };


      class B : public A
      {
      public:
      int Fn2( int x ) { return 0; }
      // ...
      };

      // Assume the methods are defined and the classes are completed elsewhere

      typedef int (B::*BMemFn)( int x );
      BMemFn f = &B::Fn2; // Is this OK?

      // Two examples of how I am using f:
      B b_obj;


      int main()
      {

      int r = (b_obj.*f)( 5 );

      A *a_ptr = new B;


      r = ( ( static_cast<B*> ( a_ptr ) )->*f)( 5 );
      }

      Having said that, I suspect you're doing somthing that you could
      probably do with virtual methods. Why not use use vritual methods ?

      G

      Comment

      • Yu Hu

        #4
        Re: question about method pointers and subclasses

        In article <bj3fl9$21q@dis patch.concentri c.net>,
        Gianni Mariani <gi2nospam@mari ani.ws> wrote:[color=blue]
        >Yu Hu wrote:
        >[color=green]
        >> Visual C++ and g++ permit me to do this, but I wanted to know if this
        >> generally should work.
        >>
        >>[/color]
        >
        >Funny - after I remove some compiler errors, gcc says:
        >
        >aaa.cpp:19: error: cannot convert `int (B::*)(int)' to `int (A::*)(int)' in
        >
        >I suspect that you're out of luck. What you tried to do is illegal.[/color]

        Oops. I typed the code from memory and forgot that it required an
        explicit cast before it would compile, as the other response to my
        original post pointed out. My mistake; in the future I'll run it through
        a compiler before posting. :)
        [color=blue]
        >Having said that, I suspect you're doing somthing that you could
        >probably do with virtual methods. Why not use use vritual methods ?[/color]

        This was the first C++ code added to the system, and the way we were
        serializing our data would not have worked with objects with vtable
        pointers.

        I am implementing finite state machines. I wish to avoid using separate
        classes for each state, although I've seen that pattern used in a lot of
        places. There are many machines being processed simultaneously, with
        many different types, so the system wants to call them only through the
        common Machine superclass interface.

        Machine::Proces sInput needs to switch on the FSM's current state to call
        the correct method to handle the input. I can only think of two ways
        to do this. One is for ProcessInput to be virtual, and for each subclass
        to override this method and use a switch statement there to call the
        correct processing method for each state. The other is to store an array
        of method pointers, and to index into it (assuming your state is an
        offset into the array) to get the right method. Because I couldn't use
        virtual methods (see above), I had to use the second option. Does anyone
        know of a better way?

        If I am allowed to use virtuals, I am definitely considering it. We're
        moving our entire code base from C to C++ and other programmers want to
        use virtual methods, so someone is going to have to solve the problems
        with serialization and such. If so, the only remaining question is
        whether writing a table of method pointers is less cumbersome than
        writing a switch table to select the correct method.

        Thanks for the response; thinking about using virtuals here has helped
        shed some light on the problem.


        --
        yph@cs.stanford .edu

        Comment

        • Yu Hu

          #5
          Re: question about method pointers and subclasses

          In article <vlagdkpr5c8v75 @news.supernews .com>,
          Andrey Tarasevich <andreytarasevi ch@hotmail.com> wrote:[color=blue][color=green]
          >> AMemFn f = &B::Fn2; // Is this OK?[/color]
          >
          >This will not compile. Member pointer types are contravariant, not
          >covariant. The following, however, is perfectly legal
          >
          > AMemFn f = static_cast<AMe mFn>(&B::Fn2);[/color]

          Oops. My mistake, I forgot the cast was necessary.
          [color=blue]
          >There are obvious dangers in such conversions, so it is up to you to
          >decide whether it is OK or not OK to do it in your code.[/color]

          Yes, that's the main reason I am not entirely happy with it. So I guess
          the question is whether I prefer to use the method pointers, or if I
          prefer having virtual methods which switch on the state to select the
          correct method to call (see my other post in this thread). The latter is
          probably safer.
          [color=blue][color=green]
          >> // Two examples of how I am using f:
          >> B b_obj;
          >> int r = (b_obj.*f)( 5 );
          >>
          >> A *a_ptr = new B;
          >> r = (a->(*f))( 5 );[/color]
          >
          >In the second case you probably meant
          >
          > r = (a_ptr->*f)(5);[/color]

          Oops again. Yes, I was just being sloppy.
          [color=blue]
          >Yes, it is guaranteed to work by C++ standard.[/color]

          Thanks for the confirmation of that. I may decide not to use them, but I
          still had an academic curiosity about whether or not it was ok.


          --
          yph@cs.stanford .edu

          Comment

          Working...