Back to C++
2026-01-167 min read

Function objects (C++)

Learn Function objects (C++) step by step with clear examples and exercises.

Why This Matters

Function objects are a crucial aspect of C++ that allow you to treat functions as first-class citizens, just like other data types such as integers or strings. They offer a unique blend of function and object capabilities, providing greater flexibility, efficiency, and reusability in your code. This guide will delve into the world of function objects, explaining their importance, prerequisites, core concept, worked example, common mistakes, practice questions, and frequently asked questions.

Why This Matters

Function objects are essential for several reasons:

  1. Flexibility: They enable you to customize the behavior of algorithms by providing a function object that defines the specific operations required.
  2. Efficiency: Function objects can be more efficient than traditional functions because they can store state information and avoid function call overhead.
  3. Reusability: Function objects can be reused across multiple algorithm invocations, making your code cleaner and more modular.
  4. Readability: By encapsulating complex logic within function objects, you can make your code easier to understand and maintain.
  5. Performance: In some cases, function objects can offer better performance than traditional functions due to their ability to avoid the overhead of function calls and to store state information.

Function objects are particularly useful in standard library algorithms like std::sort or std::for_each, where they allow you to customize the sorting criteria or perform operations on each element during iteration.

Prerequisites

To fully understand function objects, you should be familiar with:

  1. Basic C++ syntax and control structures (loops, conditionals)
  2. Object-oriented programming concepts in C++ (classes, inheritance, polymorphism)
  3. Function pointers and lambda expressions
  4. Standard Template Library (STL) concepts, including iterators, containers, and algorithms
  5. Understanding of classes, objects, and member functions
  6. Familiarity with operator overloading in C++

Core Concept

A function object is an object that overloads the operator() to call a function. This allows you to treat functions as objects, enabling you to store them in variables, pass them as arguments to other functions, and return them from functions.

Function objects can be created in several ways:

  1. Class with an overloaded operator(): A simple example is the Plus class that adds two integers:
class Plus {
public:
int operator()(int a, int b) {
return a + b;
}
};
  1. Lambda expressions: Lambda functions are anonymous function objects that can be defined inline:
auto plus = [](int a, int b) { return a + b; };
  1. Standard Library Function Objects: C++ provides several predefined function objects in the ` header, such as std::plus, std::minus, and std::multiplies`.

Function objects can be used with STL algorithms like std::for_each:

#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>

int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
std::for_each(v.begin(), v.end(), [](int i) { std::cout << i * 2 << " "; });
return 0;
}

Function Object Classes

Function object classes are regular C++ classes that overload the operator() to call a function. These classes can contain member variables and methods, allowing them to store state information and perform complex operations.

class Counter {
public:
explicit Counter(int start) : count(start) {}

void operator()(int value) {
++count;
}

int getCount() const {
return count;
}

private:
int count;
};

In this example, the Counter class overloads operator() to increment a counter each time it is called. The counter can also be accessed through the getCount() method.

Worked Example

Let's create a custom sort function that sorts elements based on their frequency in the vector:

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

class FrequencyComparator {
public:
explicit FrequencyComparator(const std::vector<int>& v) : frequencies(v.size(), 0) {
for (const auto& i : v)
++frequencies[i];
}

bool operator()(const int a, const int b) {
return frequencies[a] > frequencies[b];
}

std::vector<int> getFrequencies() const {
return frequencies;
}

private:
std::vector<int> frequencies;
};

int main() {
std::vector<int> v = {5, 3, 4, 2, 5, 3, 4, 2};
std::sort(v.begin(), v.end(), FrequencyComparator(v));
for (const auto& i : v)
std::cout << i << " ";
std::cout << "\nFrequencies:\n";
for (const auto& freq : ((FrequencyComparator(v)).getFrequencies())) {
std::cout << freq << ": " << std::count(v.begin(), v.end(), freq) << "\n";
}
return 0;
}

In this example, the FrequencyComparator class overloads operator() to compare two integers based on their frequency in the vector. It also provides a method to retrieve the frequencies for debugging purposes.

Common Mistakes

  1. Forgetting to overload operator(): A function object must overload the operator() to be a valid function object.
  2. Misusing function objects with non-compatible algorithms: Some STL algorithms, like std::transform, require a unary function object (one that takes a single argument), while others, like std::for_each, require a binary function object (one that takes two arguments). Be sure to consult the algorithm's documentation for its requirements.
  3. Creating unnecessary function objects: When using predefined function objects from the `` header, be aware of their existence to avoid reinventing the wheel.
  4. Not properly managing state: If your function object maintains state information, ensure that it is correctly initialized and updated during each call to operator().
  5. Ignoring const correctness: When overloading operator(), make sure to consider whether the function object should be const or non-const, and adjust its behavior accordingly.
  6. Not considering move semantics: If your function object contains expensive resources like large arrays or complex objects, consider implementing move constructors and assignment operators to improve performance.
  7. Overlooking copy elision: In some cases, the compiler may optimize away the copying of temporary function objects, a process known as copy elision. Be aware of this optimization when writing your code.
  8. Not understanding operator overloading: A solid understanding of operator overloading in C++ is crucial for creating effective function objects. Familiarize yourself with the various operators that can be overloaded and their usage.
  9. Ignoring lambda expressions: Lambda expressions provide a concise way to create anonymous function objects, making them an essential tool in your C++ arsenal. Learn how to use them effectively.
  10. Not considering performance implications: Function objects can offer better performance than traditional functions due to their ability to store state information and avoid the overhead of function calls. However, they can also introduce additional memory usage and complexity. Be mindful of these trade-offs when designing your function objects.

Practice Questions

  1. Write a function object that checks if an integer is even.
  2. Implement a custom sort function that sorts elements based on their absolute value.
  3. Create a function object that calculates the factorial of a number.
  4. Modify the FrequencyComparator class to also provide a method for sorting in descending order.
  5. Write a function object that computes the maximum and minimum values in a range.
  6. Implement a function object that reverses the order of elements in a range.
  7. Create a function object that counts the number of occurrences of each unique value in a range.
  8. Write a function object that finds the median of a range.
  9. Modify the Counter class to also provide a method for resetting the counter.
  10. Implement a function object that performs binary search on a sorted range.

FAQ

What is the difference between a functor and a function object?

A functor is a generic term for any class that can be called like a function, while a function object is a specific type of functor that overloads operator(). In C++, all function objects are functors, but not all functors are function objects.

Can I use function objects with pointers to functions?

Yes! Function objects can be used wherever a pointer to a function is required. This is particularly useful when you want to pass custom behavior to algorithms that expect function pointers as arguments.

How do I create a function object from a lambda expression?

To create a function object from a lambda expression, simply store the lambda in a variable of type std::function or one of the predefined function objects from the `` header:

auto plus = [](int a, int b) { return a + b; };
auto myPlus = std::plus<int>(); // equivalent to above lambda expression

What are some common use cases for function objects?

Function objects can be used in various scenarios, such as:

  1. Customizing the behavior of STL algorithms like std::sort, std::for_each, and std::transform.
  2. Implementing custom comparison functions for data structures like std::map or std::set.
  3. Defining custom arithmetic operations for use with containers like std::vector or std::array.
  4. Creating custom visitor patterns for traversing data structures.
  5. Encapsulating complex logic within reusable modules.
  6. Implementing custom policies for template metaprogramming.
  7. Defining custom actions for event-driven programming.
  8. Simplifying the implementation of callbacks and delegates.
Function objects (C++) | C++ | XQA Learn