Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I found this code sample in this answer by Armen Tsirunyan.

class MyClass
{
   public:
   typedef void (*funcPtr)(int, int);
   MyClass(funcPtr whatToCall)
   { 
     callme = whatToCall;
   }
   void myClass::callMain()
   {  
       callSomeApi(callme, <some arguments>);  //callme function pointer is passed as argument
   }
private:
   funcPtr callme;
};

void f(int a, int b) {blah blah blah};


int main()
{
   MyClass myObject(f);
   myObject.callMain(); //will call the api function with f passed as argument
}

I would like to know the advantages to use such a function pointer as a class member. If there are more, I should be overwhelmed to their uses and calls. Do you have some tips to help me memorise its usage?

share|improve this question
    
Thank you Anna for having editted my posts. It was my fault that I didn't pay so much to post details to get the most help from others. Your advice I think is very considerate. Again, thank you. –  Baby Dolphin Aug 12 '11 at 19:11
1  
add comment

5 Answers 5

Function pointers as class members are very useful for customization. The example I'm most familiar with comes from Delphi's visual component library, but it would be equally valid for C++.

Delphi ships with a widget library called the VCL. There's a control for a form, a control for a button, a control for a textbox, etc. Each of these is its own class. It has a form designer so you can create forms visually. But once you do that, all you have is a layout. Then what?

This is where function pointers come in. If you placed a button on the form, you need to specify what that button is supposed to do. It has a function pointer member for that. You write an event handler (a method whose signature corresponds to the signature of the function pointer) and attach it to the button's OnClick event, (event = function pointer,) and then at runtime, when you click the button, there's code that says "if this event handler is assigned, call it."

That makes the button customizable beyond the basic functionality that's built into it. For stuff like generic widgets, that's essential, because they can't hard-code what the button is supposed to do in your program into the basic button object. Events and event handlers is a very useful pattern to know anytime you need to write a similarly customizable object.

share|improve this answer
    
Well, although not directly related to what I am looking for, I am thankful for your time to post. –  Baby Dolphin Aug 12 '11 at 18:31
add comment

Quite simply, they shouldn't, and should never be used unless you have to be binary compatible. Boost, TR1 and C++0x all offer a vastly superior solution in the form of function<>, a class template which can accept function pointers and function objects like those produced by bind and lambda functions. Function pointers are a major code smell in C++.

Basically, they are code that can be swapped in and out at run-time. This enables you to write code that performs a function without having to actually know what that function does- Mason provides the excellent example of a button. Without such function objects, it would be near impossible to write a generic button.

share|improve this answer
    
Function pointers are very useful for interfacing with C code, or even c++ where you need to be cross-compiler. A lot of libraries use callbacks for simplicity –  Martin Beckett Aug 12 '11 at 18:28
    
Thank you MG a lot, –  Baby Dolphin Aug 12 '11 at 18:28
    
@Martin: Boost is cross-compiler, and so is TR1 and C++0x. C interop is binary compatibility, more or less. –  DeadMG Aug 12 '11 at 19:11
4  
@DeadMG - boost is usable by any compiler. But it doesn't enforce an ABI, so you can't assume a function<> class with arguments on VC++ can link to a g++ lib. –  Martin Beckett Aug 12 '11 at 19:28
1  
Another extremely common usage is for callbacks to asynchronous methods. Unfortunately, since so many libraries are written to be C compatible, you are often forced into function pointers. (For example: pthreads.) –  Steven Burnap Aug 20 '12 at 19:52
show 3 more comments

Function pointers are critical for customizing runtime engines that need to be able to call user specified code in response to known events. The biggest utility of a function pointer is the callback.

Consider a graphics library. Let's suppose that you're writing a class-based graphics library. You want the user to be able to specify their own Draw function so they can draw whatever they want, but you want your library to call their Draw function any time the screen needs to be redrawn (maybe the draw window was covered up by another window for a moment, or maybe the draw window was minimized and maximized again) - regardless of why, you want your library to handle it without the user having to call it over and over again. (That's part of the whole point of your library, right?)

Well, how can your library possibly know what function to call? You've got a couple of options. First, you could insist that they name their function void Draw() and include it somewhere that your library can get to.. not particularly useful. The second is you can allow your library to accept a function pointer to their draw function:

class BabyDolphinDrawLibrary
{
private:
    void (*RedrawCallback)();

public:
    void OnRedraw( void(*redrawCallback)() );
    void Redraw();
};

void BabyDolphinDrawLibrary::OnRedraw( void(*redrawCallback)() )
{
    RedrawCallback = redrawCallback;
}

void BabyDolphinDrawLibrary::Redraw()
{
    RedrawCallback();
}

Then, the user specifies they want some function they've declared to be called by your code any time a redraw needs to happen:


#include "BabyDolphinDrawingLibrary.h"
void myDrawingCode()
{
   // daVinci eat your heart out.
}

int main()
{
    BabyDolphinDrawLibrary render;
    render.OnRedraw(myDrawingCode);

    render.Redraw();
}

This is a fairly rough example, as graphics engines generally don't get instantiated as an object, but this gives you an example of how it gets put to use. Similarly with buttons on a GUI, as @Mason Wheeler pointed out. You have a GUI framework, and the button has something along the lines of an OnClick function pointer. You tell the Button what function to call when it's clicked.

share|improve this answer
2  
Although if you have a language with inheritance you could simply make ThisButton inherit from a abstract button and implement the on-click method. Really vtables are just function pointers behind the scenes –  Martin Beckett Aug 12 '11 at 18:26
    
Thank you, that's a long post of help. –  Baby Dolphin Aug 12 '11 at 18:28
add comment

Sorry for the double-answer, but seeing the original post makes it a lot more clear what you're looking for, and it's a related but kind of different use of function pointers. What you have there is a callback.

Let's say you want a function to download a file from the Internet. So you write:

void DownloadFile(std::string URL, std::string discLocation);

Now, that's great, right up until you try to download a very large file. Suddenly DownloadFile is taking a long time to finish, and you don't know how long it'll be. Boy, things would be a lot easier if you only had a progress indicator of some sort to let you know how far along you are! But DownloadFile can't return until it's finished, and you don't want to teach DownloadFile itself about your progress indicator, because that would lead to high coupling and make it harder to reuse DownloadFile in another context.

What you can do instead is give it a callback, a function pointer that DownloadFile uses to call you back after you call it. In fact, you'd probably want two:

void DownloadFile(std::string URL, std::string discLocation,
  intFunction FileSize, intFunction FileProgress);

(Where intFunction is a function pointer that takes one int as an argument.) It would call FileSize once to set the size of the file, and FileProgress repeatedly to inform you of how far along it is in the download. With these two pieces of information available, you can wire up a progress bar or some other type of progress indicator, without having to couple DownloadFile directly to the progress bar control.

That's the sort of power that callbacks make available. You see them a lot in code that deals with long-running events. Downloads, for example, or code for playing sound and music. In a music callback, you can perform custom edits to the sound as it's being played to add effects, or read the sound buffer and display a representation of it on an equalizer.

share|improve this answer
    
I read and left forgotting to post a "thank you" message. I like Programmer page of stackexchange, it is full of theoritical detailed explanation about almost everything. I find them very helpful. Thank you a lot. –  Baby Dolphin Aug 12 '11 at 19:27
    
@Baby Dolphin: Glad I can help. :) –  Mason Wheeler Aug 12 '11 at 19:31
add comment

The alternative to have a class store a function pointer for a callback is having a class store an instance of a callback class. You can do that like this:

class MyCallbackClass
{
 public:
 virtual void CallbackFunction(int param1, int param2)=0;
};

Now, instead of: funcPtr callme; Use MyCallbackClass *callme;

Call it with callme->CallbackFunction(param1, param2);

Create the callback with:

class SomeCallback : public MyCallbackClass
{
 public:
 SomeCallBack() { ; }
 virtual int CallbackFunction(int p1, int p2)
 {
  // callback code goes here
 }
};

Then initialize 'callme' to a new SomeCallBack();

This is much more the "C++ way" than function pointers. It tends to be much more elegant in complex cases -- especially where more than one callback is needed. But it tends to be ugly in simpler cases, especially because you have to create an instance of the callback class, which is pure ugly if the callback class doesn't need any member variables. If it does need member variables, that's actually a plus and then the callback class approach really shines.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.