Virtual function pointers (& multiple inheritance?)

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Josh Lessard

    Virtual function pointers (& multiple inheritance?)

    Hi all. I'm maintaining a C++ program and I've come across a nasty piece
    of code that works, but I just don't understand why. I'm not actually
    this part of the program, but I really want to know how and why it works.

    I'll post a simplified version of it below and ask my questions
    afterwards:

    class Base {
    void *function_ptr;

    public:
    Base();
    void Initialize();
    virtual void Function();
    };

    Base::Base() {
    function_ptr = (void *)&Base::Functi on;
    }

    void Base::Initializ e() { // should be called from derived constructor
    if ( function_ptr != (void *)&Base::Functi on ) {
    /* do something */
    }
    }

    void Base::Function( ) {
    /* some code */
    }


    class Derived : public virtual Base {
    public:
    Derived();
    virtual void Function();
    };

    Derived::Derive d() {
    Initialize();
    }

    void Derived::Functi on() {
    /* some code */
    }


    So the derived class overrides the virtual function "Function". Now, when
    the derived class calls Initialize (which is non-virtual and defined in
    the base), the statements between the curly braces in the if clause
    actually get executed. Why does this work? It seems like the base is
    setting function_ptr to &Base::Function , but then when it checks it again
    in Initialize(), they're no longer equal.

    Does this have anything at all to do with the fact that Base is a virtual
    base class (ie would this still work if it wasn't a virtual base)? As far
    as I knew, virtual bases are used only to prevent multiple copies of the
    base class in a multiple inheritance tree, but recent discussion in this
    newsgroup has caused me to wonder if there isn't (quite a bit) more to it
    than that.

    Thanks in advance for any help.

    *************** *************** *************** ********
    Josh Lessard
    Master's Student
    School of Computer Science
    Faculty of Mathematics
    University of Waterloo
    (519)888-4567 x3400
    Waterloo's Cheriton School of Computer Science is home to world-renowned faculty committed to excellence in teaching and advancing computer science research.

    *************** *************** *************** ********

  • Ron Natalie

    #2
    Re: Virtual function pointers (& multiple inheritance?)


    "Josh Lessard" <jrlessar@plg2. math.uwaterloo. ca> wrote in message
    news:Pine.SOL.4 .44.03110518351 70.26502-100000@plg2.mat h.uwaterloo.ca. ..
    [color=blue]
    > function_ptr = (void *)&Base::Functi on;[/color]

    This isn't a legitmate cast. No guarantee that a member function pointer can be cast
    to void* safely.

    What are you trying to do?



    Comment

    • Andrey Tarasevich

      #3
      Re: Virtual function pointers (&amp; multiple inheritance?)

      Josh Lessard wrote:[color=blue]
      > ...
      > I'm maintaining a C++ program and I've come across a nasty piece
      > of code that works, but I just don't understand why. I'm not actually
      > this part of the program, but I really want to know how and why it works.
      > ...[/color]

      There's no way to say why it works. Your code is broken (see Ron's
      reply) and its behavior is undefined. It might appear to be "working" if
      you are lucky and if the weather is right. And tomorrow it might start
      to crash consistently.

      --
      Best regards,
      Andrey Tarasevich

      Comment

      • lilburne

        #4
        Re: Virtual function pointers (&amp; multiple inheritance?)

        Ron Natalie wrote:
        [color=blue]
        > "Josh Lessard" <jrlessar@plg2. math.uwaterloo. ca> wrote in message
        > news:Pine.SOL.4 .44.03110518351 70.26502-100000@plg2.mat h.uwaterloo.ca. ..
        >
        >[color=green]
        >> function_ptr = (void *)&Base::Functi on;[/color]
        >
        >
        > This isn't a legitmate cast. No guarantee that a member function pointer can be cast
        > to void* safely.
        >
        > What are you trying to do?
        >[/color]

        Isn't it obvious?

        Someone has exploited a compiler bug to determine whether
        Initialize is being called in the constructor of Base or
        not. The comment the idiot left says as much.

        Comment

        • lilburne

          #5
          Re: Virtual function pointers (&amp; multiple inheritance?)

          lilburne wrote:
          [color=blue]
          > Ron Natalie wrote:
          >[color=green]
          >> "Josh Lessard" <jrlessar@plg2. math.uwaterloo. ca> wrote in message
          >> news:Pine.SOL.4 .44.03110518351 70.26502-100000@plg2.mat h.uwaterloo.ca. ..
          >>
          >>[color=darkred]
          >>> function_ptr = (void *)&Base::Functi on;[/color]
          >>
          >>
          >>
          >> This isn't a legitmate cast. No guarantee that a member function
          >> pointer can be cast
          >> to void* safely.
          >>
          >> What are you trying to do?
          >>[/color]
          >
          > Isn't it obvious?
          >
          > Someone has exploited a compiler bug to determine whether Initialize is
          > being called in the constructor of Base or not. The comment the idiot
          > left says as much.
          >[/color]

          PS: Your compiler is converting the cast to be an actual
          address (BTW this wont compile on some other compilers). In
          the constructor of Base this is taken as the actual address
          of Base::Function, but in the Initialize method it is
          probably being read from the vtable.

          Try testing it to see what happens if you call Initialize
          from Base constructor or with a class that doesn't override
          Function.

          Comment

          • Josh Lessard

            #6
            Re: Virtual function pointers (&amp; multiple inheritance?)

            > > function_ptr = (void *)&Base::Functi on;[color=blue]
            >
            > This isn't a legitmate cast. No guarantee that a member function pointer can be cast
            > to void* safely.[/color]

            In this case, it doesn't have to be a "safe cast". The sole purpose of
            function_ptr is to compare it to the Base::Function address in the
            Initialize() function to see if the function has been overridden in a
            derived class.

            What it appears to be doing is assigning &Base::Funct ion into function_ptr
            in the constructor, and then comparing function_ptr to &Base::Funct ion in
            Initialize(). What throws me off kilter is that if Base::Function has
            actually been overridden in Derived, they're no longer equal. Why not?
            [color=blue]
            > What are you trying to do?[/color]

            I didn't write the code. I'm extending a project that was written back in
            1997. As I said in my earlier post, I'm not touching this code...I'm just
            very curious as to why it works.

            What the original coder was trying to do was check to see if a derived
            class has overridden any of the virtual functions in the base class. His
            method works...I'm just at a loss to understand why.

            *************** *************** *************** ********
            Josh Lessard
            Master's Student
            School of Computer Science
            Faculty of Mathematics
            University of Waterloo
            (519)888-4567 x3400
            Waterloo's Cheriton School of Computer Science is home to world-renowned faculty committed to excellence in teaching and advancing computer science research.

            *************** *************** *************** ********

            Comment

            • Josh Lessard

              #7
              Re: Virtual function pointers (&amp; multiple inheritance?)

              > In this case, it doesn't have to be a "safe cast".

              The above sentence one of those things I wish I could have taken back just
              after I'd sent it. Believe me, I understand what was meant when you said
              it wasn't a safe cast. I agree with you...the code is pretty ugly in
              places.

              All I meant is that nothing is really done with the function pointer,
              except to compare it to the address of the function in the base class
              (which is where it was taken from anyway).

              In any case, it appears that this is working by pure fluke...so I don't
              feel so bad that I didn't understand it when I came across it.

              Thanks for your replies!

              *************** *************** *************** ********
              Josh Lessard
              Master's Student
              School of Computer Science
              Faculty of Mathematics
              University of Waterloo
              (519)888-4567 x3400
              Waterloo's Cheriton School of Computer Science is home to world-renowned faculty committed to excellence in teaching and advancing computer science research.

              *************** *************** *************** ********

              Comment

              • Ron Natalie

                #8
                Re: Virtual function pointers (&amp; multiple inheritance?)


                "Josh Lessard" <jrlessar@plg2. math.uwaterloo. ca> wrote in message
                news:Pine.SOL.4 .44.03110522344 90.2974-100000@plg2.mat h.uwaterloo.ca. ..[color=blue][color=green][color=darkred]
                > > > function_ptr = (void *)&Base::Functi on;[/color]
                > >
                > > This isn't a legitmate cast. No guarantee that a member function pointer can be cast
                > > to void* safely.[/color]
                >
                > In this case, it doesn't have to be a "safe cast".[/color]

                Safe doesn't enter into it. The compiler doesn't have to even accept it.
                No where in the docs for reinterpret_cas t does it say you can cast a pointer
                to member function to void*. In many implementations they aren't even the
                same size.
                [color=blue]
                > The sole purpose of
                > function_ptr is to compare it to the Base::Function address in the
                > Initialize() function to see if the function has been overridden in a
                > derived class.[/color]

                Yes and it only coincidentally works for that. As I said, on many implementations
                the cast won't even compile. On others, it may not give you the same prediction.
                [color=blue]
                > What the original coder was trying to do was check to see if a derived
                > class has overridden any of the virtual functions in the base class. His
                > method works...I'm just at a loss to understand why.
                >[/color]
                It's pure coincidence. You can't support that code. Once the compiler changes
                it may cease to work suddenly. It's dubious that it works at all.


                Comment

                • Ron Natalie

                  #9
                  Re: Virtual function pointers (&amp; multiple inheritance?)


                  "Josh Lessard" <jrlessar@plg2. math.uwaterloo. ca> wrote in message
                  news:Pine.SOL.4 .44.03110522500 60.2974-100000@plg2.mat h.uwaterloo.ca. ..
                  [color=blue]
                  >
                  > All I meant is that nothing is really done with the function pointer,
                  > except to compare it to the address of the function in the base class
                  > (which is where it was taken from anyway).
                  >[/color]
                  You're not even guaranteed that. void* isn't a parking place for an arbitrary
                  pointer, it's a parking place for an arbitrary object pointer. Pointers to functions
                  and any sort of pointer to member are not validly converted to void*. Many
                  compilers will refuse to even attempt such a conversion.


                  Comment

                  • Josh Lessard

                    #10
                    Re: Virtual function pointers (&amp; multiple inheritance?)

                    On Thu, 6 Nov 2003, Ron Natalie wrote:
                    [color=blue]
                    > It's pure coincidence. You can't support that code. Once the compiler changes
                    > it may cease to work suddenly. It's dubious that it works at all.[/color]

                    I agree with you 100%. Your answers here have just confirmed my
                    suspicions, and I don't feel so bad for not understanding what the hell
                    was going on and why it was "working." :P

                    Maybe it's time I ordered myself a copy of the C++ standard. I've been
                    picking up bits and pieces of it by lurking around in this newsgroup, but
                    it would be nice to be able to confirm things like this for myself.

                    Thanks again for your time.

                    *************** *************** *************** ********
                    Josh Lessard
                    Master's Student
                    School of Computer Science
                    Faculty of Mathematics
                    University of Waterloo
                    (519)888-4567 x3400
                    Waterloo's Cheriton School of Computer Science is home to world-renowned faculty committed to excellence in teaching and advancing computer science research.

                    *************** *************** *************** ********



                    Comment

                    • Grzegorz Sakrejda

                      #11
                      Re: Virtual function pointers (&amp; multiple inheritance?)

                      On Wed, 5 Nov 2003 18:52:58 -0500, Josh Lessard
                      <jrlessar@plg2. math.uwaterloo. ca> wrote:
                      [color=blue]
                      > Hi all. I'm maintaining a C++ program and I've come across a nasty piece
                      > of code that works, but I just don't understand why. I'm not actually
                      > this part of the program, but I really want to know how and why it works.
                      >
                      > I'll post a simplified version of it below and ask my questions
                      > afterwards:
                      >
                      > class Base {
                      > void *function_ptr;
                      >
                      > public:
                      > Base();
                      > void Initialize();
                      > virtual void Function();
                      > };
                      >
                      > Base::Base() {
                      > function_ptr = (void *)&Base::Functi on;
                      > }
                      >
                      > void Base::Initializ e() { // should be called from derived constructor
                      > if ( function_ptr != (void *)&Base::Functi on ) {
                      > /* do something */
                      > }
                      > }
                      >
                      > void Base::Function( ) {
                      > /* some code */
                      > }
                      >
                      >
                      > class Derived : public virtual Base {
                      > public:
                      > Derived();
                      > virtual void Function();
                      > };
                      >
                      > Derived::Derive d() {
                      > Initialize();
                      > }
                      >
                      > void Derived::Functi on() {
                      > /* some code */
                      > }
                      >
                      >
                      > So the derived class overrides the virtual function "Function". Now,
                      > when
                      > the derived class calls Initialize (which is non-virtual and defined in
                      > the base), the statements between the curly braces in the if clause
                      > actually get executed. Why does this work? It seems like the base is
                      > setting function_ptr to &Base::Function , but then when it checks it again
                      > in Initialize(), they're no longer equal.[/color]

                      Expression &Base::Funct ion maybe evaluated through virtual table , in this
                      case , when Initialized is called from Derived &Base::Funct ion will return
                      pointer related to overriden Function.

                      This all is not regulated in the standard. Proper way to store pointers to
                      member function is void (Base::*ptr)() type not a void * type.

                      You may try to replace void * by the above and try again.

                      [color=blue]
                      >
                      > Does this have anything at all to do with the fact that Base is a virtual
                      > base class (ie would this still work if it wasn't a virtual base)? As
                      > far
                      > as I knew, virtual bases are used only to prevent multiple copies of the
                      > base class in a multiple inheritance tree, but recent discussion in this
                      > newsgroup has caused me to wonder if there isn't (quite a bit) more to it
                      > than that.
                      >
                      > Thanks in advance for any help.
                      >
                      > *************** *************** *************** ********
                      > Josh Lessard
                      > Master's Student
                      > School of Computer Science
                      > Faculty of Mathematics
                      > University of Waterloo
                      > (519)888-4567 x3400
                      > http://www.cs.uwaterloo.ca
                      > *************** *************** *************** ********
                      >
                      >[/color]



                      --
                      grzegorz

                      Comment

                      • Andrey Tarasevich

                        #12
                        Re: Virtual function pointers (&amp; multiple inheritance?)

                        Grzegorz Sakrejda wrote:[color=blue]
                        > ...
                        > Expression &Base::Funct ion maybe evaluated through virtual table , in this
                        > case , when Initialized is called from Derived &Base::Funct ion will return
                        > pointer related to overriden Function.
                        >
                        > This all is not regulated in the standard. Proper way to store pointers to
                        > member function is void (Base::*ptr)() type not a void * type.
                        >
                        > You may try to replace void * by the above and try again.
                        > ...[/color]

                        In general case this won't make much of a difference. When a pointer
                        that points to a virtual function is involved in equality comparison,
                        the result is unspecified.

                        --
                        Best regards,
                        Andrey Tarasevich

                        Comment

                        Working...