Menu
Coddy logo textTech

Funktoren & Lambda-Ausdrücke

Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy. Lektion 74 von 104.

Viele STL-Algorithmen akzeptieren ein aufrufbares Objekt, das ihr Verhalten anpasst. Du hast bereits gesehen, wie Lambdas mit std::transform verwendet werden. Sehen wir uns sowohl Funktoren als auch Lambda-Ausdrücke an – zwei Möglichkeiten, aufrufbare Objekte in C++ zu erstellen.

Ein Functor (Funktionsobjekt) ist eine Klasse, die den operator() überlädt, sodass Instanzen wie Funktionen aufgerufen werden können:

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

struct MultiplyBy {
    int factor;
    MultiplyBy(int f) : factor(f) {}
    
    int operator()(int x) const {
        return x * factor;
    }
};

int main() {
    std::vector<int> nums = {1, 2, 3, 4};
    std::vector<int> result(nums.size());
    
    std::transform(nums.begin(), nums.end(), result.begin(), MultiplyBy(3));
    // result: {3, 6, 9, 12}
}

Jede Funktorinstanz kann über bei der Konstruktion gesetzte Membervariablen ihren eigenen unabhängigen Zustand enthalten – etwas, das ein gewöhnlicher Funktionsaufruf nicht kann. Die Definition einer Klasse für einfache Operationen ist jedoch umständlich. Lambda-Ausdrücke bieten eine kompakte Alternative:

int factor = 3;
std::transform(nums.begin(), nums.end(), result.begin(),
               [factor](int x) { return x * factor; });

Die Lambda-Syntax lautet [capture](parameters) { body }. Die Capture-Klausel legt fest, auf welche Variablen außerhalb die Lambda-Funktion zugreifen kann. Verwende [=], um alle Variablen per Wert zu erfassen, [&], um alle per Referenz zu erfassen, oder liste bestimmte Variablen wie [factor] oder [&factor] auf.

Lambdas sind besonders nützlich für einmalige Operationen mit Algorithmen wie dem Sortieren nach benutzerdefinierten Kriterien:

std::vector<int> nums = {5, -2, 8, -1};
std::sort(nums.begin(), nums.end(), 
          [](int a, int b) { return std::abs(a) < std::abs(b); });
// Sortiert nach Absolutwert: {-1, -2, 5, 8}
challenge icon

Aufgabe

Einfach

Erstellen wir einen Preisrechner, der sowohl Funktoren als auch Lambda-Ausdrücke demonstriert, um verschiedene Rabattstrategien auf Produktpreise anzuwenden.

Du organisierst deinen Code über zwei Dateien:

  • Discounts.h: Definiere hier deine Rabattfunktoren und Hilfsfunktionen.

    Erstelle einen Funktor namens PercentageDiscount, der einen Rabattprozentsatz (als Ganzzahl) speichert. Sein operator() soll einen double-Preis entgegennehmen und den reduzierten Preis zurückgeben. Beispielsweise sollte ein Rabatt von 20 % auf 100 $ den Wert 80 $ zurückgeben.

    Erstelle einen weiteren Funktor namens FixedDiscount, der einen festen abzuziehenden Betrag (als double) speichert. Sein operator() soll einen Preis entgegennehmen und den Preis abzüglich des festen Betrags zurückgeben (jedoch niemals einen Wert unter 0).

    Erstelle eine Funktion namens printPrices, die einen const std::vector<double>& entgegennimmt und alle Preise durch Leerzeichen getrennt ausgibt, gefolgt von einem Zeilenumbruch. Formatiere jeden Preis mit zwei Dezimalstellen.

  • main.cpp: Lies fünf Eingaben ein (jede in einer eigenen Zeile):
    1. Preis des ersten Produkts (double)
    2. Preis des zweiten Produkts (double)
    3. Preis des dritten Produkts (double)
    4. Anzuwendender prozentualer Rabatt (Ganzzahl, z. B. 20 für 20 %)
    5. Fester Rabattbetrag (double)

    Erstelle einen Vektor mit den drei Preisen und demonstriere beide Ansätze:

    1. Gib Original prices: gefolgt von den Preisen aus
    2. Verwende std::transform mit deinem PercentageDiscount-Funktor, um einen neuen Vektor mit reduzierten Preisen zu erstellen. Gib After percentage discount: gefolgt von den Ergebnissen aus
    3. Verwende std::transform mit deinem FixedDiscount-Funktor auf den ursprünglichen Preisen, um einen weiteren Vektor zu erstellen. Gib After fixed discount: gefolgt von den Ergebnissen aus
    4. Verwende std::transform mit einem Lambda-Ausdruck, der jeden ursprünglichen Preis verdoppelt. Gib Premium prices (doubled): gefolgt von den Ergebnissen aus
    5. Verwende std::sort mit einem Lambda, um die ursprünglichen Preise absteigend zu sortieren. Gib Sorted (high to low): gefolgt von den sortierten Preisen aus

Beispielsweise mit den Eingaben 100.00, 50.00, 75.00, 20 und 15.00:

Original prices: 100.00 50.00 75.00 
After percentage discount: 80.00 40.00 60.00 
After fixed discount: 85.00 35.00 60.00 
Premium prices (doubled): 200.00 100.00 150.00 
Sorted (high to low): 100.00 75.00 50.00 

Diese Aufgabe ermöglicht dir, Funktoren (die ihren Zustand wie den Rabattbetrag beibehalten) mit Lambdas (die Variablen für schnelle, inline ausgeführte Operationen erfassen) zu vergleichen. Beide Ansätze funktionieren nahtlos mit STL-Algorithmen wie std::transform und std::sort.

Probier es selbst

#include <iostream>
#include <vector>
#include <algorithm>
#include "Discounts.h"

int main() {
    // Eingaben lesen
    double price1, price2, price3;
    int percentageDiscount;
    double fixedDiscount;
    
    std::cin >> price1;
    std::cin >> price2;
    std::cin >> price3;
    std::cin >> percentageDiscount;
    std::cin >> fixedDiscount;
    
    // Erstelle einen Vektor mit den drei Preisen
    std::vector<double> prices = {price1, price2, price3};
    
    // TODO: Print "Original prices:" followed by the prices using printPrices
    
    // TODO: Use std::transform with PercentageDiscount functor
    // Erstelle einen neuen Vektor für die Ergebnisse
    // Print "After percentage discount:" followed by the results
    
    // TODO: Use std::transform with FixedDiscount functor on original prices
    // Erstelle einen neuen Vektor für die Ergebnisse
    // Print "After fixed discount:" followed by the results
    
    // TODO: Use std::transform with a lambda that doubles each original price
    // Erstelle einen neuen Vektor für die Ergebnisse
    // Print "Premium prices (doubled):" followed by the results
    
    // TODO: Use std::sort with a lambda to sort original prices in descending order
    // Print "Sorted (high to low):" followed by the sorted prices
    
    return 0;
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-C++-Compiler