Skip to main content
GameDev.net gamedev.net
🔒 Locked

C++ Function Pointer - Is it possible to generalize it?

Started by Faraday Jan 25, 2008 at 9:36 PM 9 replies 2.1k views
Original Post
Faraday
Faraday
Say if I have

class Test
{
public:
   void (*FunctionPointer)(void);
}
Then I can get FunctionPointer to point to and call a generic C style function like so:

void Function( void )
{
  // process
}
void main()
{
  Test t;
  t.FunctionPointer = &Function
  t.FunctionPointer();
}
But sending a class method in the same manner doesnt seem to work, like this:

class AnotherClass
{
public:
  void Function( void );
}
void main()
{
  Test t;
  AnotherClass ac;

  t.FunctionPointer = &(ac.Function);
}
Carrying on like this to call the function pointer results in C2440 error in VC++ (function pointer wont evaluate). Why doesnt it work? Logically it looks similar enough to the C version.
Faraday
Faraday
Thank you Antheus. It seems like a good safety net. The "generalization" there is incredible, and not quite the extent I had expected. I'm not wanting generalization in parameters, but rather call methods in generic C functions and member functions in a class.

Why doesn't my code in the 1st post work, do you know? I can't help but feel that there must be a simple solution for this. Push comes to shove, I don't see the difference between:

AnotherClass ac;
ac.Function();

and

Function();

Once 'ac' is made, so long as within its scope, I would have thought they can be treated the same. Why can't I?
Jan-Lieuwe
Jan-Lieuwe
Quote:
Original post by Faraday
Thank you Antheus. It seems like a good safety net. The "generalization" there is incredible, and not quite the extent I had expected. I'm not wanting generalization in parameters, but rather call methods in generic C functions and member functions in a class.

Why doesn't my code in the 1st post work, do you know? I can't help but feel that there must be a simple solution for this. Push comes to shove, I don't see the difference between:

AnotherClass ac;
ac.Function();

and

Function();

Once 'ac' is made, so long as within its scope, I would have thought they can be treated the same. Why can't I?


The function pointer points to a function taking no arguments. The non-static class member function requires the this pointer of the class (internally 'this' is the first argument passed to the function, so '(void)' in a non-static member function is not the same as '(void)' in a C function).

Static functions in a class don't require the this pointer, so they behave like regular C functions (but have limited scope).
ToohrVyk
ToohrVyk
Quote:
Original post by Faraday
Why doesn't my code in the 1st post work, do you know? I can't help but feel that there must be a simple solution for this. Push comes to shove, I don't see the difference between:

AnotherClass ac;
ac.Function();

and

Function();

Once 'ac' is made, so long as within its scope, I would have thought they can be treated the same. Why can't I?


The reason for this impossibility is simple: C++ does not support closures, as closures usually do not mix well with non-garbage-collected languages.

In a language which supports closures (and clean function abstractions), it's possible. For instance, in OCaml:

class anotherClass = object  method func () = 91end;;let func () = 42;;(* 'func' is a function *)let (a : unit -> int) = func;;let ac = new anotherClass;;(* 'ac # func' is a function *)let (b : unit -> int) = ac # func;;
Antheus
Antheus
Quote:
Original post by Faraday
Thank you Antheus. It seems like a good safety net. The "generalization" there is incredible, and not quite the extent I had expected. I'm not wanting generalization in parameters, but rather call methods in generic C functions and member functions in a class.


struct Test {  typedef boost::function<void(int)> MyFunction;  void foo() {}  MyFunction func;};void bar() {}...Test t;t.func = std::bind1st( std::mem_fun(&Test::foo), &t); // one optiont.func = &bar  // other optiont.func(); // call it


Quote:
Once 'ac' is made, so long as within its scope, I would have thought they can be treated the same. Why can't I?


As explained, you need some way to store "this" pointer, which is otherwise passed by implicitly.
Rhalin
Rhalin
I had to look into this a few years back. The C++ Faq Lite is your friend ;)

As Driv3MeFar mentioned Pointers to member functions is a good place to start.

The general notion here though, is don't. Section 33.10 of the faq goes over the concept of Functionoids, which does what you're looking for, even if it is a little bit more clunky.

But basically instead of calling a member function of the object itself, you create a -seperate- object derived from a base class with an overloaded function that you can change. In this way you can pass around these objects with similar member functions that can all be called the same way. Read the FAQ though, it goes far more in depth with code examples.

Faraday
Faraday
Thanks guys... especially regarding implicit this pointer being passed internally.

Good grief. So C and C++ style function pointers arent compatible. On the surface it feels so counter intuitive, but on the other hand it's a Columbus' Egg, isn't it. It makes sense after a while.

The funny thing is, some things I used to solve using C function pointers now dont really always need C++ function pointers. In some circumstances, my personal conclusion is that when calling a method of 1 class from another, in a C sort of circumstance, it seems its much tidier to rely on pure virtual class, then derive a class for each differing processing. So:
class Interface{ public:  virtual ~Interface() = 0;  virtual CallBack() = 0;};

Then derive a class and define CallBack(). Then pass the address of that object to the main class (which manages the control path) and store it in a member data "Interface *callback". Then callback->CallBack(). This will standardize calling methodology, while altering runtime functionality.

On the other (original) prob I had, I was trying to "consolidate" C and C++ function pointers. It seems there is no simple way here as you guys have pointed out these are inherently not compatible due to *this pointer. So... Ive now written a wrapper which has 2 member data, each dealing with C/C++ side.

Combine both, and that gets pretty robust (thanks Rhalin for functionoids suggestion). Thanks all. Very helpful and thoughtful.

Edit: I forgot to say in the 1st post, I was trying achieving all this without templates.
Zahlman
Zahlman
Quote:
Original post by Faraday
Thanks guys... especially regarding implicit this pointer being passed internally.

Good grief. So C and C++ style function pointers arent compatible. On the surface it feels so counter intuitive, but on the other hand it's a Columbus' Egg, isn't it. It makes sense after a while.


They aren't "C and C++ style". Well, not exactly. Function pointers were often involved in implementing your own polymorphism in C. In C++, you can usually solve the problem quite effectively by just using the built-in polymorphism, i.e. virtual functions. But the only reason you didn't have what you are calling "C++ style" function pointers (i.e. pointers to member functions) in C is that C doesn't have member functions in the first place.

What are you *really* trying to do?

Quote:
The funny thing is, some things I used to solve using C function pointers now dont really always need C++ function pointers. In some circumstances, my personal conclusion is that when calling a method of 1 class from another, in a C sort of circumstance, it seems its much tidier to rely on pure virtual class, then derive a class for each differing processing.


Oh, I guess you already had the realization, then. :)
Faraday
Faraday
Zalham, yes I've had quite a few realizations in this thread. Thanks :) Especially for future reference, for invoking arbiturary member methods this has been a good lesson.

My original problem was this -

I had written a high precision timer class, which manages various intervals and trigger callback functions when that interval has passed (be it 0.01 sec or 10 secs). I wanted it to be as abstract as possible, so that I can throw any animation class methods or regular C functions at it... you get the picture.

In C I used to do this using arrays of function pointers, but because I was using class objects this time, I had to make that leap of faith. Then I ran into that problem.

As I remarked earlier, it seems much tidier to use interface class, with virtual callback method. Then derive everything from it which I will need to callback. Then no need for function pointers in cases like this. Really neat. Why didn't I think of this earlier :D

I still needed to write a wrapper to handle both normal functions and class members in the same handle though.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.