Iteratoren
Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy — Lektion 72 von 104.
Iteratoren sind Objekte, die als Brücke zwischen Containern und Algorithmen fungieren. Sie bieten eine einheitliche Möglichkeit, auf Elemente in jedem Container zuzugreifen, unabhängig davon, wie dieser Container seine Daten intern speichert. Stellen Sie sich einen Iterator als einen verallgemeinerten Zeiger vor, der weiß, wie man sich durch einen Container bewegt.
Jeder STL-Container bietet begin() und end() Methoden an. Der begin() Iterator zeigt auf das erste Element, während end() auf die Position hinter dem letzten Element zeigt – ein Sentinel, der markiert, wo gestoppt werden soll:
#include <vector>
#include <iostream>
int main() {
std::vector<int> nums = {10, 20, 30};
for (std::vector<int>::iterator it = nums.begin(); it != nums.end(); ++it) {
std::cout << *it << " "; // Dereferenzieren, um den Wert zu erhalten
}
// Ausgabe: 10 20 30
}Das Schlüsselwort auto vereinfacht Iterator-Deklarationen erheblich:
for (auto it = nums.begin(); it != nums.end(); ++it) {
*it *= 2; // Elemente über Iterator modifizieren
}
// nums ist jetzt {20, 40, 60}Iteratoren werden basierend auf ihren Fähigkeiten in verschiedene Kategorien unterteilt. Random-Access-Iteratoren (wie die von vector) unterstützen arithmetische Operationen wie it + 3 oder it1 - it2.
Bidirektionale Iteratoren (von list, map) können sich mit ++ und -- vorwärts und rückwärts bewegen. Vorwärts-Iteratoren können sich nur in eine Richtung bewegen.
Für das rückwärtsgerichtete Durchlaufen verwenden Sie rbegin() und rend():
for (auto rit = nums.rbegin(); rit != nums.rend(); ++rit) {
std::cout << *rit << " "; // Ausgabe in umgekehrter Reihenfolge
}Aufgabe
EinfachLassen Sie uns ein Inventarverfolgungssystem erstellen, das Iteratoren verwendet, um Sammlungen von Elementen zu durchlaufen und zu manipulieren. Sie werden üben, verschiedene Iteratortypen zu verwenden, um auf unterschiedliche Weise durch Daten zu navigieren.
Sie werden Ihren Code auf zwei Dateien verteilen:
Inventory.h: Definieren Sie eineInventory-Klasse, die eine Sammlung von Artikelmengen verwaltet, die in einemstd::vector<int>gespeichert sind.Ihre Klasse sollte diese Methoden bereitstellen:
addItem(int quantity)— fügt dem Inventar eine Artikelmenge hinzuprintForward()— verwendet Iteratoren mitbegin()undend(), um alle Mengen durch Leerzeichen getrennt auszugeben, gefolgt von einem ZeilenumbruchprintReverse()— verwendet Reverse-Iteratoren mitrbegin()undrend(), um alle Mengen in umgekehrter Reihenfolge durch Leerzeichen getrennt auszugeben, gefolgt von einem ZeilenumbruchdoubleAll()— verwendet Iteratoren, um den Vektor zu durchlaufen und jede Menge an Ort und Stelle zu verdoppelngetTotal()— verwendet Iteratoren, um die Summe aller Mengen zu berechnen und zurückzugeben
Verwenden Sie das Schlüsselwort
autofür Ihre Iteratordeklarationen, um den Code sauber zu halten.main.cpp: Lesen Sie vier Ganzzahleingaben (jede in einer separaten Zeile) ein, die Artikelmengen darstellen.Erstellen Sie ein
Inventory-Objekt und fügen Sie alle vier Mengen hinzu. Demonstrieren Sie dann die Verwendung von Iteratoren durch:- Ausgabe von
Forward:gefolgt vom Aufruf vonprintForward() - Ausgabe von
Reverse:gefolgt vom Aufruf vonprintReverse() - Ausgabe von
Total: <sum>unter Verwendung vongetTotal() - Aufruf von
doubleAll(), um die Mengen zu ändern - Ausgabe von
After doubling:gefolgt vom Aufruf vonprintForward() - Ausgabe von
New total: <sum>unter Verwendung vongetTotal()
- Ausgabe von
Zum Beispiel mit den Eingaben 10, 25, 15 und 30:
Forward: 10 25 15 30
Reverse: 30 15 25 10
Total: 80
After doubling: 20 50 30 60
New total: 160Diese Herausforderung ermöglicht es Ihnen, sowohl das Lesen von Elementen über Iteratoren (zum Drucken und Summieren) als auch das Ändern von Elementen über Iteratoren (zum Verdoppeln) zu üben. Sie werden auch sehen, wie Reverse-Iteratoren das Rückwärtsdurchlaufen ohne Indexmanipulation einfach machen.
Spickzettel
Iteratoren sind Objekte, die eine einheitliche Möglichkeit bieten, auf Elemente in Containern zuzugreifen. Sie fungieren als verallgemeinerte Zeiger, die wissen, wie man sich durch einen Container bewegt.
Jeder STL-Container bietet die Methoden begin() und end() an. Der begin()-Iterator zeigt auf das erste Element, während end() auf die Position hinter dem letzten Element zeigt:
std::vector<int> nums = {10, 20, 30};
for (std::vector<int>::iterator it = nums.begin(); it != nums.end(); ++it) {
std::cout << *it << " "; // Dereference to get value
}Verwenden Sie das Schlüsselwort auto, um Iterator-Deklarationen zu vereinfachen:
for (auto it = nums.begin(); it != nums.end(); ++it) {
*it *= 2; // Modify elements through iterator
}Iterator-Kategorien basierend auf ihren Fähigkeiten:
- Random access iterators (z. B.
vector) unterstützen arithmetische Operationen wieit + 3oderit1 - it2 - Bidirectional iterators (z. B.
list,map) können sich mit++und--vorwärts und rückwärts bewegen - Forward iterators können sich nur in eine Richtung bewegen
Für den rückwärtigen Durchlauf verwenden Sie rbegin() und rend():
for (auto rit = nums.rbegin(); rit != nums.rend(); ++rit) {
std::cout << *rit << " "; // Prints in reverse order
}Probier es selbst
#include <iostream>
#include "Inventory.h"
using namespace std;
int main() {
// Lies vier Ganzzahl-Eingaben ein
int q1, q2, q3, q4;
cin >> q1;
cin >> q2;
cin >> q3;
cin >> q4;
// TODO: Erstelle ein Inventory-Objekt
// TODO: Füge alle vier Mengen zum Inventar hinzu
// TODO: Gib "Forward: " aus und rufe dann printForward() auf
// TODO: Gib "Reverse: " aus und rufe dann printReverse() auf
// TODO: Gib "Total: " aus, gefolgt vom Ergebnis von getTotal()
// TODO: Rufe doubleAll() auf, um die Mengen zu modifizieren
// TODO: Gib "After doubling: " aus und rufe dann printForward() auf
// TODO: Gib "New total: " aus, gefolgt vom Ergebnis von getTotal()
return 0;
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienC++ Build & KompilierungHeader-Dateien & QuelldateienNamensräume & GültigkeitsbereicheEinführung in OOP in C++Klassen vs. ObjekteDer 'this'-PointerMethoden (Elementfunktionen)Attribute (Datenelemente)Grundlagen zu Ctors & DtorsRückblick - Einfacher Taschenrechner4Klasseneigenschaften
Instanz- vs. statische MemberGetter und SetterConst-MemberfunktionenMutable-SchlüsselwortStatische Methoden und VariablenFriend-Funktionen & KlassenZusammenfassung - Bankkonto-Manager7Vererbung
Grundlagen der VererbungZugriffsstufen bei VererbungAufrufreihenfolge von Ctor & DtorÜberschreiben von MethodenVirtuelle Funktionen & VTableMehrfachvererbungVirtuelle VererbungRückblick - Mitarbeiter-Hierarchie2Speicherverwaltung
Stack vs. Heap SpeicherZeiger und ReferenzenDynamischer Speicher (new/delete)Smart Pointers in C++RAII in C++Rückblick – Dynamischer Array-Manager5Kapselung
Zugriffsspezifizierer in C++Zugriffsspezifizierer im DetailInformation HidingStruct vs. ClassVerschachtelte & innere KlassenRückblick - Studentenverwaltungssystem8Polymorphie
Kompilierzeit- vs. Laufzeit-PolymorphieFunktionsüberladungVirtuelle Funktionen – WiederholungRein virtuelle FunktionenAbstrakte KlassenInterface-Design in C++Dynamic Casting & RTTIZusammenfassung – Formen-Rechner3Konstruktoren & Destruktoren
StandardkonstruktorParametrisierter KonstruktorKopierkonstruktorVerschiebekonstruktorKonstruktor-InitialisierungslistenDelegierende KonstruktorenDestruktoren im DetailRule of Three / Five / ZeroZusammenfassung - String-Klasse6Operatorüberladung
Einführung in die OperatorüberladungArithmetische OperatorüberladungVergleichsoperatorüberladungStream-OperatorenZuweisungsoperatorüberladungÜberladen der [] und () OperatorenTypumwandlungsoperatorenRückblick - Matrix-Klasse9Templates
FunktionstemplatesKlassentemplatesTemplate-SpezialisierungVariadische TemplatesSFINAE & Type Traits GrundlagenRückblick - Generische Container