Link to home
Start Free TrialLog in
Avatar of helpmealot
helpmealot

asked on

Function ptr -> void * -> Function ptr

I have this code, which does not compile.

  { void (CTestaesr23Dlg::*pfnwSC)(void);
    m_Map.SetAt ("func", (void *) &pfnwSC);
  }

  //void (CTestaesr23Dlg::*pfn) (void) = &CTestaesr23Dlg::func;
  //(this->*pfn)();

  { void (CTestaesr23Dlg::*pfn) (void);
    void *apfn;
    m_Map.Lookup ("func", apfn);
    pfn = (void (CTestaesr23Dlg::*)(void)) apfn;
    (this->*pfn)();
  }

Essentially, I want to make a map of strings to member function pointers.  That is, given a string, I want a pointer to a class member function.  I am using the MFC class CMapStringToPtr because I think this is what's necessary.

Unfortunately, I can't seem to figure out how to cast a void * pointer back to a void (CTestaesr23Dlg::*)(void) pointer.  Is this how I approach the problem?  What am I doing wrong?

Thanks for any help.
Avatar of Triskelion
Triskelion
Flag of United States of America image

How many functions do you have?
If it's only a few, you may be able to use just a static struct with both the strings and the pointers to functions.
You can't use
pfn = (void (CTestaesr23Dlg::*)(void)) apfn;
because it protected by compiler.
but you can cheat it with this:
memcpy((void*)&pfn, apfn, sizeof(apfn));
ASKER CERTIFIED SOLUTION
Avatar of DanRollins
DanRollins
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
One important point.  When using the "myThis" technique, you need to remember that the object (CMyDlg) must be a singleton.  If you instantiate another copy of the object, the static myThis will be wrong.

-- Dan
Avatar of smitty1276
smitty1276

I had that problem before... I don't remember how well it worked, but I think I used a static member function and a static pointer to an instance of the class, which I would set before calling the function... I think.  It was a while back.

class myClass
{
  int myData;
 
  //static member func and static pointer
  static void staticFunc( void );
  static MyClass *currentInstance;
}

static void myClass::staticFunc( void )
{
  cout << currentInstance->myData << endl;
}

You can then use it like this...
Supposing you want to call the staticFunc() function of the instance inst...

myClass inst;

//set pointer to desired instance
MyClass::currentInstance = &inst;

//call the member function (or a pointer to it, or whatever)
MyClass::staticFunc();


It looks like DanRollins already said essentially the same thing I did... sorry.
BTW, DanRollins, I don't agree with this:
>The problem is that you can't call member fn, except static
> member fns, through a pointer.

You can call even a none-static member function against an
object through a pointer exactly as helpmealot does it:
(this->*pfn)();
Avatar of helpmealot

ASKER

I think I have found a solution that seems to be most straightforward.

Rather than use the CMapStringToPtr class, I've switched to the CMap class, which uses templates.

I now have the following code, which does compile and works perfectly:

-------

void CTestaesr23Dlg::OnButton1()
{ CMap<CString, LPCSTR, void (CTestaesr23Dlg::*) (void), void (CTestaesr23Dlg::*) (void)> m_Map;

  { m_Map.SetAt ("func", func);
    m_Map.SetAt ("func2", func2);
  }

  { void (CTestaesr23Dlg::*pfn) (void);
    m_Map.Lookup ("func", pfn);
    (this->*pfn)();

    void (CTestaesr23Dlg::*pfn2) (void);
    m_Map.Lookup ("func2", pfn2);
    (this->*pfn2)();
  }
}

------------------

func and func2 are both executed.
>> BTW, DanRollins, I don't agree with this:
>> >The problem is that you can't call member fn, except static
>> > member fns, through a pointer

You are right.  This works:

typedef void (CMyDlg::*VFuncPtrToMember_v)(void);

void CMyDlg::OnButton1()
{
    VFuncPtrToMember_v  pfnNonStatic= DoSomething; // non-static
    (this->*pfnNonStatic)();
}

Thanks Zoppo, I have learned something new today and am a better man because of it!
-==-=-=-=--==-=-=-

helpmealot,
It looks like you solved this one yourself.  I have one tip, though.  If you use a typedef, the code is quite a bit cleaner:

typedef void (CMyDlg::*VFnPtr_v)(void);
void CMyDlg::OnButton1()
{
    CMap<CString, LPCSTR, VFnPtr_v, VFnPtr_v> m_Map;
    m_Map.SetAt ("func", DoSomething);
    m_Map.SetAt ("func2", StopIt);

    VFnPtr_v pfn;
    m_Map.Lookup ("func", pfn);
    (this->*pfn)();
}

-- Dan
Ah good point, I hadn't thought of that.  Thank you! :)  If there are no objections, I suppose I'll delete this question in a day or two.
Actually, you should choose the comment that gave you the most advice and accept it as the answer to award the points to that expert.
Yes, you are right, I appologize.  It's only 50 points anyway.  I therefore have decided to award points to DanRollins as his comments helped me the most overall.

Thank you for the input everyone!
>Thanks Zoppo, I have learned something new today and am a better man because of it!
You're welcome...