Was sind Funktoren in C++ und wozu braucht man sie?
\n\nStellen Sie sich vor, Sie schreiben Code in C++ und müssen ein Verhalten (eine Funktion) an eine andere Funktion übergeben, z. B. zum Sortieren oder Filtern von Daten. Die klassische Lösung sind Funktionszeiger. Diese haben jedoch Nachteile: Sie speichern keinen Zustand, sind schwer inline zu setzen und wirken etwas archaisch. Hier kommen Funktoren in C++ (auch Funktionsobjekte oder funktionale Objekte C++) ins Spiel.
\n\nEin Funktor ist eine gewöhnliche Klasse oder Struktur, in der der Funktionsaufrufoperator operator() überladen ist. Dadurch kann eine Instanz einer solchen Klasse wie eine gewöhnliche Funktion verwendet werden. Klingt kompliziert? Tatsächlich ist es eines der elegantesten Werkzeuge in C++. Auf Stack Overflow hat die Frage "What are C++ functors and their uses?" tausende Aufrufe – Entwickler möchten dieses Thema verstehen, um flexibleren und leistungsfähigeren Code zu schreiben. In diesem Leitfaden erklären wir alles Schritt für Schritt: von der grundlegenden Syntax bis zu realen Anwendungsbeispielen mit der STL.
Grundlegende Syntax: Wie erstelle ich meinen ersten Funktor
\n\nDas Erstellen eines Funktors erfolgt in drei Schritten:
\n- \n
- Deklarieren Sie eine Klasse oder Struktur. \n
- Implementieren Sie darin
operator()mit der gewünschten Signatur (Parameter und Rückgabetyp). \n - Erstellen Sie ein Objekt dieser Klasse und rufen Sie es wie eine Funktion auf. \n
Hier ist ein einfaches Beispiel für einen C++ Funktor, der eine Zahl mit zwei multipliziert:
\n\n#include <iostream>\n\nclass Multiplier {\npublic:\n // Überladen des Operators ()\n int operator()(int x) const {\n return x * 2;\n }\n};\n\nint main() {\n Multiplier mult; // Erstellen des Funktionsobjekts\n std::cout << mult(5) << std::endl; // Ausgabe: 10\n std::cout << mult(10) << std::endl; // Ausgabe: 20\n return 0;\n}\n\nBeachten Sie: mult(5) sieht aus wie ein Aufruf einer gewöhnlichen Funktion, ist aber tatsächlich ein Aufruf von mult.operator()(5). Der Compiler sorgt für syntaktischen Zucker, und der Code wird sauber und intuitiv.
Hauptvorteil: Funktoren können Zustände speichern
\n\nIm Gegensatz zu gewöhnlichen Funktionen oder Lambda-Ausdrücken (vor C++11) können Funktionsobjekte in C++ eigene Member-Variablen besitzen. Dies eröffnet enorme Möglichkeiten. Sie können beispielsweise einen Funktor erstellen, der nicht nur eine Aktion ausführt, sondern sich auch merkt, wie oft er aufgerufen wurde:
\n\n#include <iostream>\n\nclass Counter {\nprivate:\n int count = 0;\npublic:\n int operator()() {\n return ++count;\n }\n int getCount() const { return count; }\n};\n\nint main() {\n Counter counter;\n std::cout << counter() << std::endl; // 1\n std::cout << counter() << std::endl; // 2\n std::cout << counter() << std::endl; // 3\n // Der Zustand bleibt zwischen den Aufrufen erhalten!\n return 0;\n}\n\nDieses Beispiel eines C++ Funktors mit Zustand kann mit einer einfachen Funktion ohne Verwendung globaler Variablen (was schlecht ist) nicht realisiert werden. Funktoren lösen dieses Problem elegant und sicher.
\n\nFunktoren und STL-Algorithmen: Die ideale Kombination
\n\nDie stärkste Anwendung von Funktoren ist die Arbeit mit Algorithmen aus der Standard Template Library (STL). Algorithmen wie std::sort, std::find_if, std::for_each erwarten als Eingabe ein aufrufbares Objekt (callable). Sie können ihnen einen Funktor übergeben, der die gewünschte Logik ausführt.
Beispiel: Sortieren mit einem Funktor
\n\nAngenommen, Sie haben einen Vektor von Zahlen und möchten diese absteigend sortieren. Sie können einen eigenen Vergleichsfunktor schreiben:
\n\n#include <iostream>\n#include <vector>\n#include <algorithm>\n\nclass Descending {\npublic:\n bool operator()(int a, int b) const {\n return a > b; // Rückg