Menu
Coddy logo textTech

std::function & std::bind

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

Während Lambdas leistungsfähig sind, müssen Sie manchmal aufrufbare Objekte mit unterschiedlichen Typen auf einheitliche Weise speichern oder bestehende Funktionen anpassen, um einer erforderlichen Signatur zu entsprechen. std::function und std::bind aus dem Header <functional> lösen diese Probleme.

std::function ist ein typlöschender Wrapper (Type-Erased Wrapper), der jedes Callable aufnehmen kann, das einer bestimmten Signatur entspricht – Funktionen, Lambdas oder Funktionsobjekte:

#include <iostream>
#include <functional>

int add(int a, int b) { return a + b; }

int main() {
    std::function<int(int, int)> operation;
    
    operation = add;                              // Reguläre Funktion
    std::cout << operation(3, 4) << "\n";        // 7
    
    operation = [](int a, int b) { return a * b; }; // Lambda
    std::cout << operation(3, 4) << "\n";        // 12
}

std::bind erzeugt ein neues Callable, indem einige Argumente einer bestehenden Funktion fixiert werden. Verwenden Sie std::placeholders::_1, _2 usw., um Argumente zu markieren, die variabel bleiben:

#include <iostream>
#include <functional>

void greet(const std::string& greeting, const std::string& name) {
    std::cout << greeting << ", " << name << "!\n";
}

int main() {
    using namespace std::placeholders;
    
    auto sayHello = std::bind(greet, "Hello", _1);
    sayHello("Alice");  // Hallo, Alice!
    
    auto swapped = std::bind(greet, _2, _1);
    swapped("Bob", "Hi");  // Hi, Bob!
}

Diese Tools sind in der OOP besonders nützlich, um Callbacks als Klassenmitglieder zu speichern oder das Strategy-Pattern zu implementieren. Modernes C++ bevorzugt jedoch oft Lambdas gegenüber std::bind für eine bessere Lesbarkeit und Performance – verwenden Sie std::bind hauptsächlich dann, wenn Sie Argumente umordnen müssen oder mit Legacy-Code arbeiten.

challenge icon

Aufgabe

Einfach

Lassen Sie uns einen konfigurierbaren Taschenrechner bauen, der die Leistungsfähigkeit von std::function und std::bind demonstriert. Sie werden ein System erstellen, in dem mathematische Operationen zur Laufzeit gespeichert, ausgetauscht und angepasst werden können – und so zeigen, wie diese Werkzeuge ein flexibles Callback-Management ermöglichen.

Sie werden Ihren Code auf drei Dateien verteilen:

  • MathOperations.h: Definieren Sie eine Sammlung von eigenständigen mathematischen Funktionen, die als Ihre Operationsbibliothek dienen.

    Erstellen Sie diese Funktionen:

    • add(int a, int b) — gibt die Summe zurück
    • subtract(int a, int b) — gibt die Differenz (a - b) zurück
    • multiply(int a, int b) — gibt das Produkt zurück
    • power(int base, int exponent, int multiplier) — gibt multiplier * (base ^ exponent) zurück. Verwenden Sie eine einfache Schleife, um die Potenz zu berechnen (gehen Sie von nicht-negativen Exponenten aus).
  • Calculator.h: Definieren Sie eine Calculator-Klasse, die std::function verwendet, um Operationen dynamisch zu speichern und auszuführen.

    Ihr Calculator sollte Folgendes haben:

    • Ein privates Mitglied std::function<int(int, int)>, um die aktuelle binäre Operation zu speichern
    • setOperation(std::function<int(int, int)> op) — setzt die aktuelle Operation
    • calculate(int a, int b) — führt die gespeicherte Operation aus und gibt das Ergebnis zurück

    Fügen Sie die erforderlichen Header (<functional>) hinzu und stellen Sie sicher, dass Sie Ihren MathOperations-Header einbinden.

  • main.cpp: Lesen Sie drei Eingaben ein:
    1. Operationsname: add, subtract, multiply oder square
    2. Erste Zahl (Ganzzahl)
    3. Zweite Zahl (Ganzzahl)

    Erstellen Sie einen Calculator und konfigurieren Sie ihn basierend auf dem Operationsnamen:

    • Für add, subtract und multiply: Weisen Sie die entsprechende Funktion direkt dem Taschenrechner zu
    • Für square: Verwenden Sie std::bind, um eine spezialisierte Version von power zu erstellen, die immer den Exponenten 2 und den Multiplikator 1 verwendet. Die gebundene Funktion sollte zwei Argumente akzeptieren, wobei nur das erste als Basis verwendet wird (das zweite Argument kann mithilfe eines Placeholders ignoriert werden).

    Nachdem Sie die Operation festgelegt haben, rufen Sie calculate() mit Ihren zwei Zahlen auf und geben Sie Folgendes aus:

    Result: [value]

    Demonstrieren Sie dann das Austauschen von Operationen, indem Sie dem Taschenrechner ein Lambda zuweisen, das a + b + 100 zurückgibt, es mit denselben Eingaben ausführen und Folgendes ausgeben:

    With bonus: [value]

Zum Beispiel mit den Eingaben add, 10 und 5:

Result: 15
With bonus: 115

Mit den Eingaben multiply, 7 und 3:

Result: 21
With bonus: 110

Mit den Eingaben square, 4 und 0:

Result: 16
With bonus: 104

Diese Herausforderung zeigt, wie std::function eine einheitliche Möglichkeit bietet, verschiedene aufrufbare Typen (reguläre Funktionen, gebundene Funktionen und Lambdas) zu speichern, während std::bind es Ihnen ermöglicht, bestehende Funktionen anzupassen, indem Sie einige ihrer Argumente festlegen.

Probier es selbst

#include <iostream>
#include <string>
#include <functional>
#include "Calculator.h"

using namespace std;

int main() {
    // Eingaben lesen
    string operation;
    int num1, num2;
    cin >> operation >> num1 >> num2;
    
    // Eine Calculator-Instanz erstellen
    Calculator calc;
    
    // TODO: Konfiguriere den Taschenrechner basierend auf dem Operationsnamen
    // Für "add", "subtract", "multiply": die entsprechende Funktion direkt zuweisen
    // Für "square": verwende std::bind, um eine spezialisierte Version von power zu erstellen,
    //   die immer den Exponenten 2 und den Multiplikator 1 verwendet
    //   Hinweis: Verwende std::placeholders::_1 für das Basis-Argument
    
    if (operation == "add") {
        // Dein Code hier
    } else if (operation == "subtract") {
        // Dein Code hier
    } else if (operation == "multiply") {
        // Dein Code hier
    } else if (operation == "square") {
        // Dein Code hier - verwende std::bind mit der power-Funktion
    }
    
    // TODO: calculate() aufrufen und das Ergebnis ausgeben
    // Format: "Result: [value]"
    
    // TODO: Demonstriere das Austauschen von Operationen
    // Weise dem Taschenrechner ein Lambda zu, das a + b + 100 zurückgibt
    // Rufe calculate() erneut auf und gib das Ergebnis aus
    // Format: "With bonus: [value]"
    
    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