Funktor
Ein Funktionsobjekt ist ein Objekt, das sich wie eine Funktion verhält. Erreicht wird das durch das Überladen des Klammeroperators in C++. Ein Funktionsobjekt wird in der C++-Community gern auch als Funktor bezeichnet. Dem Python-Programmierer sind Funktionsobjekte unter dem Namen callable object ein Begriff.
Ein Funktionsobjekt lässt sich wie eine Funktion aufrufen. Daher ist es naheliegend, einem Funktionsobjekt einen Funktionszeiger gegenüberzustellen. Listing B.1 enthält die Funktion lessLength
und das Funktionsobjekt GreaterLength
. Beide sind in Aktion im Kapitel 3, Abschnitt „Lambda-Funktionen“ zu sehen. Sie sortieren mithilfe des STL-Algorithmus std::sort
den Vektor über Strings in aufsteigender bzw. absteigender Ordnung.
bool lessLength(const std::string& f, const std::string& s){ return f.length() < s.length(); } class GreaterLength{ public: bool operator()(const std::string& f, const std::string& s) const{ return f.length() > s.length(); } }; // initialising with initializer lists std::vector<std::string> myStrVec= {"12345","123456","1234","1","12","123","12345"}; // sorting with the function pointer std::sort(myStrVec.begin(),myStrVec.end(),lessLength); // sorting with the function object std::sort(myStrVec.begin(),myStrVec.end(),GreaterLength());
Entscheidend für das Verständnis des Funktionsobjekts ist der Klammeroperator operator()
. Er sorgt dafür, dass Objekte dieser Struktur von der C++-Laufzeit als Funktionen behandelt werden. Im Ausdruck std::sort
wird GreaterLength()
instanziiert und als Sortierkriterium verwendet. Natürlich müssen die Argumente, die der Algorithmus std::sort
erwartet, wenn er einen Vektor von Strings sortieren soll, mit den Parametern des Klammeroperators zusammenpassen.
Die wichtigste Frage bleibt bestehen. Betrachten wir die Funktion LessLength
und das Funktionsobjekt GreaterThen
in Listing B.1 genauer, fällt lediglich auf, dass mehr Schreibarbeit notwendig ist, um das Funktionsobjekt zu definieren. Die Antwort auf die Frage „Welche Vorteile bietet ein Funktionsobjekt?“ lässt sich vereinfacht auf ein Wort reduzieren: Zustand.
Zustand
Ein Funktionsobjekt ist ein Objekt mit Methoden und Attributen und kann insofern einen Zustand besitzen. Das einfache Listing B.2 addiert die Werte eines Vektors und stellt das Ergebnis über die Methode getSum()
zur Verfügung. Im Attribut sum
wird der Zustand des Objekts gehalten.
sumMe.cpp
01 #include <algorithm> 02 #include <iostream> 03 04 class SumMe{ 05 private: 06 int sum; 07 08 public: 09 // init sum with 0 10 SumMe(): sum(0){}; 11 12 // add x to sum 13 void operator()(int x){ 14 sum +=x; 15 } 16 17 // get the result 18 int getSum(){ 19 return sum; 20 } 21 22 }; 23 24 int main(){ 25 26 std::vector<int> intVec= {1,2,3,4,5,6,7,8,9,10}; 27 28 // sum the values up and bind the function object to sumMe 29 SumMe sumMe= std::for_each(intVec.begin(),intVec.end(), SumMe()); 30 31 std::cout << "\n"; 32 std::cout << "Sum of intVec= " << sumMe.getSum() << std::endl; 33 std::cout << "\n"; 34 35 }
Der Algorithmus std::for_each
besitzt die besondere Eigenschaft, dass er das Funktionsobjekt zurückgibt (Zeile 29), das in diesem konkreten Fall das Ergebnis der Summation hält.
Das Ergebnis ist relativ unspektakulär: