How to cast a function pointer in C++?

I have a struct that contains as one of its members a function pointer.  The message pump has an array of these structs and loops through it each time a message is received in a TCP port, executing the handler function if there's a listener for it.  It looks like this:

struct MessageQueue
     unsigned long msgID;
     char *rawRecordData;
     void (OAtm::*handler)();

Problem is, OAtm is a base class from which different vendor classes are derived.  So, when one of the derived classes registers one of its listeners, how do I cast it from a void(OAtm::*)(void) pointer to a void(Derived::*)(void)?
LVL 14
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Why do you need to do that? I mean the MessageQueue is expecting a void(OAtm::*)(void) pointer. Did you want to cast the other way. from derived to base?
Oh I see now. you already have a function pointer but depending on the object type call one of the derived class functions. I would recommend using virtual functions. If you have control over OAtm source, you could write the handler function and call virtual function from within that handler. e.g.

class OAtm {
    virtual void handlerFunc() = 0;
    inline void handlerWrapper() { handlerFunc(); }

class Derived {
    void handlerFunc() { do something }

You could try passing the handlerFunc directly but I am not very sure how reliable it would be.
cuziyqAuthor Commented:
The problem is that the base class won't know the names of the functions that will eventually need to be overridden.

Basically, what this application does is receives raw data from various vendors.  All they need to do is send data to a TCP port that we listen on.  They provide specifications as to where the field boundaries are and what data they will contain.

The base class simply contains a raw record holder and functions to add this information into a database.  Each derived class has whatever functions it needs to crack the data into its constituent parts so that it can be passed to the database in a standardized form, echoed back to the sender, or forwarded on to a 3rd party.

Here's the kicker:
Some vendors will have dozens of messages that we'll need to process, and others will only have one or two, depending on what that vendor's line of business is.  Therefore, each derived class may need to have a dozen handler functions, or it may only need to have one or two.  With the myriad of different types of data we're handling, it's not feasible to have a virtual function in the base simply for the sake of being able to override it in a derived class.

So here was my thinking:
When the derived class wants to register one of its handler functions, it casts it as an (OAtm::*)() instead of a void(Derived::*)().

I know that casting a derived class to a base class pointer is generally bad, but since each derived class is responsible for registering its own messages, there will never be a situation where the service will be trying to follow a pointer to a function that doesn't exist.

Sorry for the long description.  I figure a background on what I am trying to do would help out a bit :-)
Build an E-Commerce Site with Angular 5

Learn how to build an E-Commerce site with Angular 5, a JavaScript framework used by developers to build web, desktop, and mobile applications.

It seems that what you are trying to do can not be done the way you want it to. You will not be able to access the derived class data once you cast to the base class, unless you cast it back to the derived. What you can do is modify the struc to:

struct MessageQueue
     unsigned long msgID;
     char *rawRecordData;
     OAtm* vendor;

the derived class will by somehting like
class deriv : public OAtm
 // data
  void handle();

and then when you call the handler use a macro to typecast the base class from the pointer 'vendor' to derived and then call the handler.
I should have asked this earlier: how is the member function called? I mean there has to be an object on which the function is invoked; where and how is that object obtained?
Consider using a functiooid instead of a simple function pointer :

It allows for a lot more flexibility, and you won't have to cast anything.
>>>> I would recommend using virtual functions.
The concept of message maps is taken from MFC where by means of a wizard you could add new handler functions for Window messages to your class. The wizard adds a new entry to a macro controled table in the cpp file of the class. Each entry of the table contains the message id(s) of the message to handle and a function pointer to a - wizard generated - member function of the class. By means of macros the function pointers were casted from a prototype defined in the baseclass of all of these classes to the 'override' function of the derived class.

The functionality of these message maps is comparable with that of virtual functions. At runtime the dispatch function of the messages finds out which class(es) was/were associated to handle a message and calls a virtual function which iterates the message maps in order to find an appropriate handler. The concept is so mighty that it even can call multiple handler functions in a class hierarchy.

The advantage over virtual functions is that there is no baseclass function needed beside of the prototyp of all handler functions and that the member functions can be named individually. Each type of handler function has its specific argument signature which was supplied by the caller and made available in the message map by an appropriate cast.

The disadvantage is the ugly casts needed. And of course you need to store the pointer of the target object with the window that dispatches the message. In MFC that is done by SetWindowLong.

>>>> How to cast a function pointer in C++?

You may look at the file afxmsg_.h in the atlmfc\include subfolder (mfc\include in VC6) where you can see the different macros for casting.
cuziyqAuthor Commented:
Yes, yes, MFC message maps are the exact model I would like to try and follow here!  I've looked at afxwin.h, but the #define macros are buried so deep it's hard to understand what's going where.  Could you demystify it for me?

When you do your BEGIN_MESSAGE_MAP(), the macro inserts some code into the file that initializes a struct with values exactly the way I want to do here.  But what I don't understand is the AFX_PMSG member of the AFX_MSGMAP struct simply translates to CCmdTarget::*.  CCmdTarget is a base class for all of MFC, and does not contain the stuff needed for, say, a CDialog.  So how does an object derived from CDialog place a function pointer in a CCmdTarget*?  My BODQ object derives from OAtm, but the struct will not accept a BODQ::* pointer (it's defined in the struct as (OAtm::*handler)(), and the compiler gives me the error "cannot convert from 'void (__thiscall BODQ::* )(void)' to 'void (__thiscall OAtm::* )(void)'.

It seems like I am doing the same kind of thing MFC is, but MFC is waaay more compilcated, so it may be obfuscating the fact that the pointer types don't match somehow.
cuziyqAuthor Commented:
I've thought about the whole functionoid idea, but it just seems convoluted to me to have a bazillion objects lying around for each of the functions that need to be executed.  Maybe I'm just not fully understanding the concept.
You just have to look at it as a safer version of function pointers that also allows for a lot more than is possible with simple function pointers.
>>>> So how does an object derived from CDialog place a function pointer in a CCmdTarget*?  

The message map is an array of a struct which expects a pointer to a member function 'void CCmdTarget::afxHandler(void)'.  To be able to insert a function with prototype 'long MyDialog::myHandler(AnyType* p1, UINT n)' you simply need a cast. That works cause the dispatch function actually would do the reverse cast and actually calls a function UnknownClass::yourHandler(AnyType* p1, UINT n) where the pointer for the 'UnknownClass' instance was stored with the window handle. Hence, the dispatcher has a valid object (more accurate a valid pointer to a object) and a known function prototype. These components were all to actually call the member function which function pointer was stored in the message map.

>>>> the compiler gives me the error "cannot convert from 'void (__thiscall BODQ::* )(void)' to 'void (__thiscall OAtm::* )(void)'.
Yes, that is the disadvantage I told of. These casts were very tricky as you need to have a chain of casts rather than one single cast to make things working.

Look at the ON_NOTIFY macro which translates to

#define ON_NOTIFY(wNotifyCode, id, memberFxn) \
      { WM_NOTIFY, (WORD)(int)wNotifyCode, (WORD)id, (WORD)id, AfxSigNotify_v, \
            (AFX_PMSG) \
            (static_cast< void (AFX_MSG_CALL CCmdTarget::*)(NMHDR*, LRESULT*) > \
            (memberFxn)) },

The interesting parts begin with


what actually is a C cast where the AFX_PMSG is a function pointer defined as

    typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);

i. e. it is a member function of CCmdTarget with void return and void (no) argument. The (AFX_PMSG) is the final cast to satisfy the type which was required by the struct which represents one entry of a MFC message map.

The 'inner' cast is a static_cast which now has the needed arguments but still is a member of CCmdTarget:

      static_cast< void (AFX_MSG_CALL CCmdTarget::*)(NMHDR*, LRESULT*) >

Ignore the AFX_MSG_CALL which is only a specifier whether the arguments are put from left to right or right to left into the stack. You see, the return vallue of the function prototype still is void, but now the function has two arguments NMHDR* and LRESULT*. If you would generate a handler for notifying - say of a list control - you exactly would have the same arguments, a NMHDR* and LRESULT*. So, the only thing the cast was casting is that it turns a CYourDialog object to its baseclass object what is a CCmdTarget. The main principle is: you can't make a cast which both changes the argument list *and* the object (class) of a member function. But you can make a cascade of cast where the inner cast changes the derived class to (one of) its base class(es) and the out cast turns the argument list to void.



Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
cuziyqAuthor Commented:
OK, I studied afxwin.h carefully, and reread your last post about a dozen times.  I don't need a chain of casts the way MFC does because the functions themselves all take the same argument list.  That just leaves the one cast from (BODQ::*)() to (OAtm::*)().

As it turns out, I was only missing one thing -- a typedef.

typedef void(OAtm::*CAST)();

Simply adding that one line, and then doing (CAST)void(BODQ::*handlerFxn)() makes it work the way I had it before I even posted this question.  Previously, I was trying something ridiculously convoluted like (void(OAtm::*)())void(BODQ::*handler)(), which obviously doesn't work.

So now, I guess the only question left is why does typedefing the cast work, but you can't do it inline?  Not really a big deal since I am happy I solved my problem.  But I am still curious.  Are there too many parenthesis to confuse the compiler or something?
>>>> why does typedefing the cast work, but you can't do it inline?

Generally, a typedef can only help, i. e. you should be able to make the cast without typedef as well.

But, I must admit that I never casted function pointers not using typedef's. I think the syntax of function pointers - exaggerated by class member function pointers - is weird and badly thought out by a *technician*. So, unfortunately, I can't help you with your final question ... or better said, it makes too much efforts to dive into that issue ;-)
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Editors IDEs

From novice to tech pro — start learning today.