Link to home
Start Free TrialLog in
Avatar of Yo081699
Yo081699

asked on

using function pointers

I have a function F1 that uses a pointer on another function:
void F1 (void (*)());
 I want to provide F1 with a pointer on a member functiion F2:
class C1
{...
void m_F2();
...}
How can I make F1 to use m_F2.?
Of course calls like F1( m_F2) don't work as m_F2 is of type void (C1::*)()
Avatar of KangaRoo
KangaRoo

You need an object to call a member function on. You cannot do this. Maybe there is another solution to the underlying problem
if the class' member function is static, the following works (verified):

class C1
{
public:
     void m_F2();
} // end class C1


     f1(&C1::m_F2);
         ...

void CSomeClass::f1 (void (*f)())
{
     f();  // call the fcn passed in
}
Sorry, didn't get complete comment in last time...

If the function is not static, this works:


typedef void (C1::*FcnPtr)(void);
FcnPtr pFcn = &C1::m_F2;
f1(pFcn);


void CSomeClass::f1 (void (C1::*f)(void))
{
     C1 c;
     (c.*f)();
}
Avatar of Yo081699

ASKER

Sure, actually captainKrik and  KangaRoo answered the question.
But they forgot the another possibility (mine):
if the function isn't static there is an undefined number of C1 instances (and m_f2) and therefore you cannot specify what m_f2 instance you want to use.( KangaRoo)
If it's static it's OK as the m_f2 you specify is the only one existing.(captainKrik)

But if the call to f1 is made from a function declared in C1 as well, the compiler ought to be able to determine the instance of C1(and therefore of m_f2) you're refering to: the one from which you're carrying out the calling.(Isnt't that what this means?)

In fact this question is hard and the compiler might not be able to do this correctly (without using some tricks such as void pointer that ought not to be necessary)
Yes Captain, ypur comment is OK but I have to use an existing C1 object.
The pointer you give to f1 is a relative pointer that represent the position of m_f2 in a C1 object.
Anyway f1 is declared as void (*)() not void(C1::*)()
How would the compiler know that you'd only be calling f1 from one specific object. Or relate back to the object that called f1 in the first place?
What if f1 is called from a completely different function?

BTW captainKirk, I think it should be
  F1(C1::m_F2);
without the & operator
I think I made to many assumptions on captainkirk's example. It is completely wrong: you cannot call non-static member functions from a static member function without an object:

class A
{
   void m1(){}
   static void s1(){}
   static void s2
   {
      s1(); // legal
      m1(); // illegal
      A a;
      a.m1(); // legal
   }

}
I am sorry captain, seems your last piece of code is correct. Guess it's getting late and I'm having problem undestanding all those tiny letters here. See ya.
There are two options to making this work.  In brief:

1.  change the code to use pointer-to-member type pointers.  (From you question, I gather you are familar with these, right?)

2.  Use an static member or global interface function.  This is a static member function or a non-member fuctuon that would take a pointer to an object as one of its parameters.  It would then call the appropriate member function of the specified object.
I found a solution but I don't know if the needed keyword exists:
I want each instance of my C1 class to include a copy a m_f2 . I could then use the address called to determine which instance of C1 to use.
each time you create an instance of your C1 class, you get a copy of any member variables in the class and those are specific to the class instance - this would include member functions, I would think...
>> you get a copy of any member variables in the
>> class and those are specific to the class instance -
>> this would include member functions,
nope.  Objects don't store member functions, just data members.  

But that doesn't matter.   That suggests you have a case where you have an object to work with, right?  If you have a case where you have an object to work with, then you can then call one of the object's member functions.  No problem.  but in the original question you seem to indicate that you don't have an object to work with.

There are two solutions to this problem.  
of course m_f2 works with C1 !
The problem is for m_f2 to know which C1 object to work with.
Do you know the keyword I asked for?(To force member functions to be duplicated)
You're not listening.  There is no such keyword.  member function's can't be duplicated.  Ignore captain kirk on this one, he's in hyperspace.

There are two solutions to the problem.  The two I presented.

To call a non-static member function you must have 2 pieces of information.  You must have the object to be used (or apointer/reference to it) and you must have a pointerr to the the function to be called.  The is no way to determine 1 piece given the other, you must have both.

If you were to provide more details about your situation, I might be able to help you to apply one of the solutions I suggested to your case.
Yes master nietod.
I created a static member REF in C1 for the calling C1 object reference (which contains both m_f2 and the function calling f1)
The function  first copies 'this' into REF and then call f1 with m_f2 address.
m_f2 uses the REF member to determine which C1 called it, and everyone's happy.
But I can't cast m_f2 address to type
void(*)(). Is there a way to cast it or have I to use something like inline assembly or unions?
This is probably NOT what you wanted, but a cleaner? solution (or at least more general :) would be the approach used in the STL. They define function objects, and also adaptors (that take normal functions and make function objects from them).

A function object would be any object that overloads operator() (since I can use it like a function).

Some code that could make this work follows (complete running progam, compiled with djgpp):

There may be a better way, and/or we can re-use the stuff defined in the STL, but righ now, for me, it was easier to write it than to go check the STL :) (not that I'm arguing for that as a general solution :)

#include <iostream>
using namespace std;

class VoidFun {
public:
      virtual void operator()(void) = 0;
};

class C1 {
public:
      int a;
      C1() {a=0;}
      void m_f2(void) {a++; cout << "In C1::m_f2 " << a << endl; }
};

class VoidC1Fun :public VoidFun {
private:
      C1 c;
public:
      VoidC1Fun(C1 pc) { c=pc;}
      virtual void operator()(void) {c.m_f2();}
};

class VoidVoidFun: public VoidFun {
private:
      void (*f)(void);
public:
      VoidVoidFun(void (*pf) (void) ) {f=pf;}
      virtual void operator()(void) { f();}
};

void f(void)
{
      cout << "In f" << endl;
}



// this will be your function
void somefun(VoidFun &f)
{
      cout << "In somefun" << endl;
      f();
}

int main(void)
{
      VoidVoidFun vf(f);
      C1 obj;
      VoidC1Fun c(obj);

      cout << "With function pointer" << endl;
      somefun(vf);

      cout << "With member pointer" << endl;
      somefun(c);
}


>> I can't cast m_f2 address to type void(*)().
Right!  they are different types.

>> Is there a way to cast it
Yes you can make the case work, by casting the type of apointer to the pointer.  This will allow your code to compile.  But the code will crash if you attempt to do use the pointer.  This is because the code is trying to call what it thinks is a non-member function using a pointer that was a pointer to a member function.  That won't work!  

>> I to use something like inline assembly
That will also allow you to make code that compiles.  it will also crash when you use it.

>> unions?
This will crash too.

A non-static member function can never be used like a non-member function.  A non-member function can never be used like a non-static member function.  You can make such attempts compile.  But there is no point in doing so.  They will fail.

2 opions.

You must either redecare F1() so that it uses pointer-to-members.  Or you must pass it an interface function.  The interface function would then obtain the object in some way (from a parameter, or from a global variable) and then call the object's member function.

i can't image a reason wny these would not be acceptible solutions.  You want to explain why they are not?
Nietod,
First what I said works fine with VC++ as it passes the this value using the ecx register, therefore there's no problems povided you don't use the this value in m_f2.
Maybe your compiler uses the stack?

Could I redeclare f1 as a template function that would have for parameters a pointer on m_f2 and an other on the calling object?
What declaration should I make.
>> Maybe your compiler uses the stack?
Maybe.  maybe yours does too.  This is implimentation defined.  That means how it is done is up to the designers of the compiler.  That means if you relly on it being performed in a particular way, you code may fail if you: change compilers, change versions of compilers, change operating systems, possibly even if you change settings for your compiler.  Microsoft currently uses the ECX register to pass the this pointer.  But the have not really even officially documented this fact.  Consider the fact that they did pubish the calling conventiosn used for the windows API functions (which was important that they do so.)  Then when they changed from 16 to 32 bit, they changed the calling convention (reversing the order of all the parameters.)  (100's of poorly written programs failed due to this.)  They changed a published calling convention that was being explicitly rellied on by 100s of programs when they felt it was necessary, what would it take for them to change an unpubliched one that no one should be reling on?

If you had no other choice at all, it might make sense to use assembly or some other "fix" to get past this problem.  But you have good choices available.  Ones they well keep you code clean and portable.

I still don't know the exact details of what you need to do.  it hard to say what tact to take.

If you can rdeclare F1(), then you can redeclare it to take a functor (function object) that would allow you  to make use of the suggestion that cum made.  This would allow you to call F1 specifying functors that act as an interface (my suggestion 2) used to call the object's member procedure.  And also allow you to call F1 specifying regular functions.  This is a verry powerful solution, but might be overkill for your needs.

You might simply redeclare F1() so that it takes a "void *" parameter that it then passes on to the function that it calls.  This "void *" parameter could be ignored for functions that don't need extra data.  But could be used to specify a pointer to an object to be used by an interface funcion.  The interface function would then convert the "void *" pointer to the correct type and use it to call a member function.

There are other solutions (allthough they all boild down to the 2 ideas I suggested), I just don't know enough about what you need to know what is best.
I know that what I coded was poorly done else why would I have asked for another solution ?

My f1 function will be used by various objects: I want it to be declared so that the caller just has to code f1 (this, m_f2) whatever it is, a member function or not.
That's why I thought about declaring a <template T> void f1 (T*, T::*)
but I don't understand why it doesn't work... It refuses to compile, why?
I tend to not like templates, so I'm not very experienced with them, but it seems like that sort of solution should work.  (I'm not familiar with any provission in the C++ standard that would prevent it, but that doesn't mean that VC 6 is capable of supporting it.)  

However one problem is that the 2nd parameter is not the right type.  The type of a pointer-to-member function should be (I think)

(T::*)()

not

T::*

Try that.  if that doesn't work, I think I would consider simply adding a "void *" pointer parameter to the function that is called by pointer.  Then you can use this parameter to pass pointers to objects.  The weakness with this approach is that you will need to write interface functions for each member function that needs to be called of each of the classes that may be used.  If there are a lot of classes involved, or a lot of member functions that might be called, this could be a lot of interface functions.  if that is the case, you might be better of using a functor, as cum, siggested.  Do you know how many member functions/classes might need to be called in this way?
Sorry it does compile it's just VC++ that is too stupid to understand complex statements.
..
I didn't understand, I don't have to write nothing more, the compiler will instanciate a function for each calling class.
Anyway with Curri's solution I have to instanciate a VoidC1Fun for each object I have and the caller has, moreover, to write something more than f1(this, m_f2) .
>> I didn't understand, I don't have to write
>> nothing more, the compiler will instanciate a
>> function for each calling class.
I was saying that is an alternative IF the template doesn't work.  (Because VC doesn't always handle templates correctly (no compiler does!))

>> it does compile it's just VC++ that is too
>> stupid to understand complex
>> statements
What compiles?  your version?  it should not.  you should need to use the type that I suggested for the 2nd parameter.
You're right, VC++ and I are both stupid!
I because I'm not smart enough to copy here what I've written in VC++ .(I wrote it with the correct syntax void(T::*)())
VC++ because it doesn't understand
f1(this, m_f2), I had to write:
C1* a=this; void(C1*::b)()=m_f2; f1(a,b);

Ok, do you have something better than templates?
Else I don't know which comment to grant, there is no real answer . . .
Give a clear list of the possibilities I'll take it as an answer.
If the template works, go with it.
Whats wrong with the template solution?
You can request to split points (EE Customer Service). Or simply give credit to the most helpfull comment. We'll get our share eventually.

If the 'solution' to a programming problem looks strange, or is difficult to work with, it may be better to look for an alternative solution.

BTW, I don't like function pointers, I do like templates
BTW--I do like function pointers (preferably functors), I don't like templates   : - )
ASKER CERTIFIED SOLUTION
Avatar of ianB
ianB

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