ReviseAlgo Logo

Functions

Function Pointers

Pointers to functions for callbacks and dynamic dispatch

Interview: Foundation for callbacks, command patterns, and understanding how virtual dispatch works internally

Function Pointers

A function pointer is a variable that stores the address of a function. Just as a data pointer holds the address of a memory location, a function pointer holds the address of executable code. Calling through a function pointer transfers execution to that address — the foundation of callbacks, dispatch tables, and plugin architectures.

Syntax and Declaration

The syntax for function pointer types is notoriously noisy: ReturnType (*pointerName)(ParamTypes). The parentheses around *pointerName are mandatory — without them, int *f(int) declares a function returning int*, not a pointer to a function. Use using or typedef to create readable type aliases.

Function Pointers vs std::function

Raw function pointers can only point to free functions and static member functions — they cannot capture state. std::function is a type-erased wrapper that can hold any callable (lambdas, member functions, functors) at the cost of a virtual dispatch overhead. For performance-critical callbacks, raw function pointers or templates are preferred.

Virtual Function Tables (vtable)

C++ implements virtual function dispatch using an array of function pointers called the vtable. Each polymorphic class has a vtable, and each object holds a hidden vptr pointing to it. A virtual call is essentially a function pointer lookup: vptr[vtable_index](args). Understanding function pointers demystifies how virtual dispatch works at the machine level.

Interview Corner

Q: What is the difference between a function pointer and std::function?

A: A raw function pointer can only point to free functions or static members — it cannot capture state. std::function is a type-erased, heap-allocating wrapper that accepts any callable including stateful lambdas. The trade-off: raw function pointers are zero-overhead (just a pointer call), while std::function involves indirection and possible heap allocation. For hot paths, prefer raw pointers or templates; for flexible APIs, use std::function.

Q: How does C++ implement virtual function dispatch internally?

A: Each polymorphic class has a vtable — a static array of function pointers. Each polymorphic object contains a hidden vptr (pointer to its class's vtable). A virtual call like base->method() compiles to: load vptr from object, index into vtable, call the function pointer. This is exactly one extra indirection compared to a direct call — that's the cost of runtime polymorphism.

Common Pitfalls

  • Calling a null function pointer: Dereferencing a null function pointer is undefined behavior (usually a crash). Always validate before calling: if (fp) fp(args);
  • Incompatible signatures: Casting a function pointer to an incompatible signature and calling through it is undefined behavior. The parameter types and return type must match exactly.
  • Non-static member functions: Pointers to non-static member functions have a different type: ReturnType (ClassName::*ptr)(Params). They require an object instance to call through.

Best Practices

  • Use using FuncType = ReturnType(*)(Params); to create readable type aliases for function pointer types.
  • Prefer templates with callable parameters in new code — they accept lambdas, functors, and function pointers without overhead: template<typename F> void apply(F f);
  • Use std::function only when you need to store different callables in a container or across ABI boundaries.