Casting a void pointer to base class and calling overridden function ... allowed?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Bj?rn Toft Madsen

    Casting a void pointer to base class and calling overridden function ... allowed?

    Hi all,

    The network library I use communicates with my app using a callback
    function. This callback function is called with the type of message, a
    void pointer to he actual message and a user defined void pointer.

    The callback function expected is a standard C callback function. I
    have used a static class function, which I certainly know is not
    entirely correct. Bear with me, I don't think my troubles are related
    to this hack.

    When the class is constructed, I set up the network library by
    supplying the address of the static method as the callback and I also
    pass along "this" as the user defined void pointer.

    In the static method, the following takes place:
    HRESULT CDPServer::Mess ageHandler(PVOI D pvUserContext, DWORD
    dwMessageType, PVOID pMessage) {
    switch(dwMessag eType) {
    case DPN_MSGID_ADD_P LAYER_TO_GROUP:
    return ((CDPServer*)pv UserContext)->AddPlayerToGro up((PDPNMSG_ADD _PLAYER_TO_GROU P)pMessage);
    break;
    //many more cases
    }
    }

    As you can see, I cast the user defined pointer to CDPServer*.

    The issue is that naturally all these "event handlers" like
    AddPlayerToGrou p() are meant to be overridden in sub-classes of
    CDPServer:
    class CMyServer : public CDPServer {
    protected:
    //other stuff
    virtual HRESULT AddPlayerToGrou p(/*...*/);
    }

    So in effect, my static message handler casts the pointer to
    CMyServer's super class (CDPServer) and then calls the overridden
    function AddPlayerToGrou p()

    The application behaves as expected when running, but my debugger (a
    rather old MSVC++ 6.0) jumps into CDPServer::AddP layerToGroup()
    instead of CMyServer::AddP layerToGroup(). Once in there, it goes about
    executing empty lines and generally behaves weird.

    Questions that I hope somebody cleverer than I can answer:
    1) Is this approach canon?
    2) Is the fact that the debugger jumps into
    CDPServer::AddP layerToGroup() related to me using a bad approach, or
    can I chalk it up to my rather old debugger? When running, after all,
    things happen the way they are suppose to.

    My suggestions as to how these issues could be alleviated; please
    don't hesitate to comment:
    1) Use typeid to discern the correct type and thus make sure that I
    call the correct method. Isn't this what virtual does?
    2) Visitor pattern (supply a message handler object and then have
    CDPServer call functions in this) instead of deriving from CDPServer.

    Thanks in advance for any pointers you might have.
    Best regards
    Bjørn Toft Madsen
  • John Harrison

    #2
    Re: Casting a void pointer to base class and calling overridden function ... allowed?


    "Bj?rn Toft Madsen" <sunbeam60@hotm ail.com> wrote in message
    news:9349844c.0 403010546.65640 866@posting.goo gle.com...[color=blue]
    > Hi all,
    >
    > The network library I use communicates with my app using a callback
    > function. This callback function is called with the type of message, a
    > void pointer to he actual message and a user defined void pointer.
    >
    > The callback function expected is a standard C callback function. I
    > have used a static class function, which I certainly know is not
    > entirely correct. Bear with me, I don't think my troubles are related
    > to this hack.
    >
    > When the class is constructed, I set up the network library by
    > supplying the address of the static method as the callback and I also
    > pass along "this" as the user defined void pointer.
    >
    > In the static method, the following takes place:
    > HRESULT CDPServer::Mess ageHandler(PVOI D pvUserContext, DWORD
    > dwMessageType, PVOID pMessage) {
    > switch(dwMessag eType) {
    > case DPN_MSGID_ADD_P LAYER_TO_GROUP:
    > return[/color]
    ((CDPServer*)pv UserContext)->AddPlayerToGro up((PDPNMSG_ADD _PLAYER_TO_GROU P)p
    Message);[color=blue]
    > break;
    > //many more cases
    > }
    > }
    >
    > As you can see, I cast the user defined pointer to CDPServer*.
    >
    > The issue is that naturally all these "event handlers" like
    > AddPlayerToGrou p() are meant to be overridden in sub-classes of
    > CDPServer:
    > class CMyServer : public CDPServer {
    > protected:
    > //other stuff
    > virtual HRESULT AddPlayerToGrou p(/*...*/);
    > }
    >
    > So in effect, my static message handler casts the pointer to
    > CMyServer's super class (CDPServer) and then calls the overridden
    > function AddPlayerToGrou p()
    >
    > The application behaves as expected when running, but my debugger (a
    > rather old MSVC++ 6.0) jumps into CDPServer::AddP layerToGroup()
    > instead of CMyServer::AddP layerToGroup(). Once in there, it goes about
    > executing empty lines and generally behaves weird.
    >
    > Questions that I hope somebody cleverer than I can answer:
    > 1) Is this approach canon?[/color]

    I think its fine.
    [color=blue]
    > 2) Is the fact that the debugger jumps into
    > CDPServer::AddP layerToGroup() related to me using a bad approach, or
    > can I chalk it up to my rather old debugger? When running, after all,
    > things happen the way they are suppose to.[/color]

    I'd be surprised if a debugger got this wrong, I'd suspect some subtle bug
    that only manifests itself in a debug build.

    Have you compared the value of the this pointer when when you convert it to
    void with the value when you cast back from void to CDPServer*, they should
    be the same.

    john


    Comment

    • Heinz Ozwirk

      #3
      Re: Casting a void pointer to base class and calling overridden function ... allowed?

      "Bj?rn Toft Madsen" <sunbeam60@hotm ail.com> schrieb im Newsbeitrag news:9349844c.0 403010546.65640 866@posting.goo gle.com...
      : Hi all,
      :
      : The network library I use communicates with my app using a callback
      : function. This callback function is called with the type of message, a
      : void pointer to he actual message and a user defined void pointer.
      :
      : The callback function expected is a standard C callback function. I
      : have used a static class function, which I certainly know is not
      : entirely correct. Bear with me, I don't think my troubles are related
      : to this hack.
      :
      : When the class is constructed, I set up the network library by
      : supplying the address of the static method as the callback and I also
      : pass along "this" as the user defined void pointer.
      :
      : In the static method, the following takes place:
      : HRESULT CDPServer::Mess ageHandler(PVOI D pvUserContext, DWORD
      : dwMessageType, PVOID pMessage) {
      : switch(dwMessag eType) {
      : case DPN_MSGID_ADD_P LAYER_TO_GROUP:
      : return ((CDPServer*)pv UserContext)->AddPlayerToGro up((PDPNMSG_ADD _PLAYER_TO_GROU P)pMessage);
      : break;
      : //many more cases
      : }
      : }
      :
      : As you can see, I cast the user defined pointer to CDPServer*.
      :
      : The issue is that naturally all these "event handlers" like
      : AddPlayerToGrou p() are meant to be overridden in sub-classes of
      : CDPServer:
      : class CMyServer : public CDPServer {
      : protected:
      : //other stuff
      : virtual HRESULT AddPlayerToGrou p(/*...*/);
      : }
      :
      : So in effect, my static message handler casts the pointer to
      : CMyServer's super class (CDPServer) and then calls the overridden
      : function AddPlayerToGrou p()

      A problem I see is your sequence of casts:

      CCMyServer* --> void* --> CDPServer*

      This might not always work. Try static_cast<CDP Server*>(this) instead of simply this.

      HTH
      Heinz

      Comment

      Working...