C++ Function Pointer | 'Function Pointer' Guide
이 글의 핵심
int add(int a, int b) { return a + b; }.
What is Function Pointer?
A function pointer is a variable that stores the memory address of a function, allowing you to call functions indirectly. This is particularly useful for implementing callbacks, event handlers, and dynamic function selection at runtime.
In C++, function pointers enable polymorphic behavior without inheritance, making them valuable for C-style APIs and performance-critical code where virtual function overhead matters.
Below is an implementation example using C++. Understand the role of each part while examining the code.
int add(int a, int b) {
return a + b;
}
int main() {
// Declare function pointer
int (*funcPtr)(int, int) = add;
// Call
int result = funcPtr(3, 4); // 7
std::cout << result << std::endl;
}
Basic Syntax
The syntax for function pointers can look intimidating at first, but it follows a logical pattern. The key is reading it “inside-out”: int (*ptr)(int, int) means “ptr is a pointer to a function that takes two ints and returns an int.”
The parentheses around *ptr are crucial - without them, you’d be declaring a function that returns a pointer, not a pointer to a function.
Below is an implementation example using C++. Understand the role of each part while examining the code.
// Declare function pointer
int (*ptr)(int, int);
// Assign function
int add(int a, int b) { return a + b; }
ptr = add;
// Or
ptr = &add;
// Call
int result = ptr(3, 4);
// Or
int result = (*ptr)(3, 4);
Simplify with typedef/using
Function pointer syntax can become unwieldy with complex signatures. Type aliases make your code more readable and maintainable. The modern using syntax is preferred over typedef because it’s more consistent with template syntax and easier to read.
This approach is essential when working with arrays of function pointers or when passing function pointers as template parameters.
Here is detailed implementation code using C++. Import necessary modules. Understand the role of each part while examining the code.
// typedef
typedef int (*Operation)(int, int);
// using (recommended)
using Operation = int(*)(int, int);
int add(int a, int b) { return a + b; }
int multiply(int a, int b) { return a * b; }
int main() {
Operation op = add;
std::cout << op(3, 4) << std::endl; // 7
op = multiply;
std::cout << op(3, 4) << std::endl; // 12
}
Practical Examples
Example 1: Callback Function
Callbacks are one of the most common uses of function pointers. They allow you to customize behavior without modifying the core algorithm. This pattern is fundamental in event-driven programming, sorting algorithms with custom comparators, and plugin architectures.
The forEach function here demonstrates the strategy pattern - the same iteration logic can perform different operations based on the callback provided.
Here is detailed implementation code using C++. Import necessary modules, process data with loops. Understand the role of each part while examining the code.
#include <vector>
void forEach(const std::vector<int>& vec, void (*callback)(int)) {
for (int x : vec) {
callback(x);
}
}
void printValue(int x) {
std::cout << x << " ";
}
void printSquare(int x) {
std::cout << x * x << " ";
}
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
forEach(numbers, printValue); // 1 2 3 4 5
std::cout << std::endl;
forEach(numbers, printSquare); // 1 4 9 16 25
std::cout << std::endl;
}
Example 2: Calculator
This calculator example shows how function pointers enable runtime function selection. Instead of using if/switch statements, you can pass the operation as a parameter. This makes the code more extensible - adding new operations doesn’t require modifying existing functions.
This pattern is commonly used in mathematical libraries, scripting engines, and anywhere you need to select algorithms dynamically.
Here is detailed implementation code using C++. Import necessary modules. Understand the role of each part while examining the code.
using Operation = int(*)(int, int);
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }
int divide(int a, int b) { return b != 0 ? a / b : 0; }
int calculate(int a, int b, Operation op) {
return op(a, b);
}
int main() {
std::cout << calculate(10, 5, add) << std::endl; // 15
std::cout << calculate(10, 5, subtract) << std::endl; // 5
std::cout << calculate(10, 5, multiply) << std::endl; // 50
std::cout << calculate(10, 5, divide) << std::endl; // 2
}
Example 3: Function Table
Function tables (jump tables) are an efficient way to eliminate long chains of if-else or switch statements. By mapping string commands to function pointers, you can implement command processors, interpreters, or dispatch systems with O(1) lookup time.
This approach is particularly valuable in embedded systems, game engines, and anywhere performance matters more than the slight complexity overhead.
Here is detailed implementation code using C++. Import necessary modules, process data with loops, perform branching with conditionals. Understand the role of each part while examining the code.
#include <map>
#include <string>
using Command = void(*)();
void cmdHelp() {
std::cout << "Help" << std::endl;
}
void cmdQuit() {
std::cout << "Quit" << std::endl;
}
void cmdStatus() {
std::cout << "Status check" << std::endl;
}
int main() {
std::map<std::string, Command> commands = {
{"help", cmdHelp},
{"quit", cmdQuit},
{"status", cmdStatus}
};
std::string input;
while (true) {
std::cout << "> ";
std::cin >> input;
if (input == "quit") break;
auto it = commands.find(input);
if (it != commands.end()) {
it->second(); // Call function
} else {
std::cout << "Unknown command" << std::endl;
}
}
}
Example 4: Sort Comparison Function
Here is detailed implementation code using C++. Import necessary modules, process data with loops. Understand the role of each part while examining the code.
#include <algorithm>
#include <vector>
bool ascending(int a, int b) {
return a < b;
}
bool descending(int a, int b) {
return a > b;
}
bool byAbsoluteValue(int a, int b) {
return std::abs(a) < std::abs(b);
}
void sortVector(std::vector<int>& vec, bool (*compare)(int, int)) {
std::sort(vec.begin(), vec.end(), compare);
}
int main() {
std::vector<int> numbers = {-5, 2, -8, 1, 9, -3};
sortVector(numbers, ascending);
for (int x : numbers) std::cout << x << " ";
std::cout << std::endl; // -8 -5 -3 1 2 9
sortVector(numbers, descending);
for (int x : numbers) std::cout << x << " ";
std::cout << std::endl; // 9 2 1 -3 -5 -8
sortVector(numbers, byAbsoluteValue);
for (int x : numbers) std::cout << x << " ";
std::cout << std::endl; // 1 2 -3 -5 -8 9
}
std::function (C++11)
Here is detailed implementation code using C++. Import necessary modules. Understand the role of each part while examining the code.
#include <functional>
int add(int a, int b) {
return a + b;
}
int main() {
// Function pointer
int (*ptr)(int, int) = add;
// std::function (more flexible)
std::function<int(int, int)> func = add;
// Can also store lambda
func = [](int a, int b) { return a * b; };
std::cout << func(3, 4) << std::endl; // 12
}
Member Function Pointer
Here is detailed implementation code using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.
class Calculator {
public:
int add(int a, int b) {
return a + b;
}
int multiply(int a, int b) {
return a * b;
}
};
int main() {
Calculator calc;
// Member function pointer
int (Calculator::*funcPtr)(int, int) = &Calculator::add;
// Call
int result = (calc.*funcPtr)(3, 4); // 7
std::cout << result << std::endl;
// Call with pointer
Calculator* ptr = &calc;
result = (ptr->*funcPtr)(3, 4);
std::cout << result << std::endl;
}
Common Issues
Issue 1: Syntax Complexity
Below is an implementation example using C++. Import necessary modules. Try running the code directly to check its operation.
// ❌ Complex syntax
int (*funcPtr)(int, int);
// ✅ Simplify with using
using Operation = int(*)(int, int);
Operation funcPtr;
Issue 2: nullptr Check
Below is an implementation example using C++. Import necessary modules, perform branching with conditionals. Understand the role of each part while examining the code.
using Callback = void(*)();
void execute(Callback cb) {
// ❌ No nullptr check
// cb(); // Can crash
// ✅ nullptr check
if (cb) {
cb();
}
}
Issue 3: Lambda Capture
Below is an implementation example using C++. Try running the code directly to check its operation.
int x = 10;
// ❌ Lambda with capture cannot be function pointer
// void (*ptr)() = [x]() { std::cout << x; }; // Error
// ✅ Use std::function
std::function<void()> func = [x]() { std::cout << x; };
Issue 4: Member Function Pointer
Below is an implementation example using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.
class MyClass {
public:
void func() {}
};
// ❌ Cannot use regular function pointer
// void (*ptr)() = &MyClass::func; // Error
// ✅ Member function pointer
void (MyClass::*ptr)() = &MyClass::func;
MyClass obj;
(obj.*ptr)();
Function Pointer Array
Here is detailed implementation code using C++. Import necessary modules, process data with loops. Understand the role of each part while examining the code.
using Operation = int(*)(int, int);
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }
int divide(int a, int b) { return b != 0 ? a / b : 0; }
int main() {
Operation operations[] = {add, subtract, multiply, divide};
for (int i = 0; i < 4; i++) {
std::cout << operations[i](10, 5) << " ";
}
std::cout << std::endl; // 15 5 50 2
}
std::function vs Function Pointer
Here is detailed implementation code using C++. Import necessary modules. Understand the role of each part while examining the code.
#include <functional>
int add(int a, int b) { return a + b; }
int main() {
// Function pointer: Functions only
int (*ptr)(int, int) = add;
// std::function: Functions, lambdas, function objects all
std::function<int(int, int)> func1 = add;
std::function<int(int, int)> func2 = [](int a, int b) { return a * b; };
struct Multiplier {
int operator()(int a, int b) const {
return a * b;
}
};
std::function<int(int, int)> func3 = Multiplier();
}
FAQ
Q1: When to use function pointer?
A:
- Callback functions
- Function tables
- Plugin systems
Q2: std::function vs function pointer?
A:
- Function pointer: Fast, functions only
- std::function: Flexible, lambdas/function objects
Q3: Performance?
A: Function pointer is indirect call. Slight overhead.
Q4: Member function pointer?
A: Different syntax. &Class::func, (obj.*ptr)()
Q5: Need nullptr check?
A: Yes. Check recommended for safety.
Q6: Function pointer learning resources?
A:
- “C++ Primer”
- cppreference.com
- “Effective C++“
Related Articles
- C++ Observer Pointer | “Observer Pointer” Guide
- C++ invoke and apply | “Function Call” Utility Guide
- C++ Observer Pattern Complete Guide | Event-Based Architecture and Signal/Slot
Master function pointers for flexible callbacks! 🚀
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- C++ invoke와 apply | ‘함수 호출’ 유틸리티 가이드
- C++ Observer Pointer | ‘관찰 포인터’ 가이드
- C++ nullptr vs NULL | ‘널 포인터’ 가이드
이 글에서 다루는 키워드 (관련 검색어)
C++, function-pointer, callback 등으로 검색하시면 이 글이 도움이 됩니다.