Const-Memberfunktionen
Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy. Lektion 29 von 104.
Du hast das Schlüsselwort const bei Getter-Methoden in der vorherigen Lektion gesehen. Aber was bedeutet es genau, wenn const nach der Parameterliste einer Funktion erscheint? Eine const-Memberfunktion verspricht, keine Membervariablen des Objekts zu ändern.
class Rectangle {
int width;
int height;
public:
Rectangle(int w, int h) : width(w), height(h) {}
int getArea() const { // const-Memberfunktion
return width * height; // Das Lesen von Membern ist erlaubt
}
void setWidth(int w) { // Non-const - verändert das Objekt
width = w;
}
};Das const nach der Parameterliste teilt dem Compiler mit: „Diese Funktion wird den Zustand des Objekts nicht ändern.“ Wenn du versuchst, eine Membervariable innerhalb einer const-Funktion zu ändern, wird der Compiler einen Fehler ausgeben.
Dies wird bei der Arbeit mit const-Objekten oder const-Referenzen unerlässlich. Ein const-Objekt kann nur const-Memberfunktionen aufrufen:
void printArea(const Rectangle& rect) {
std::cout << rect.getArea(); // OK - getArea() ist const
// rect.setWidth(10); // FEHLER - setWidth() ist nicht const
}Funktionen als const zu kennzeichnen, wenn sie das Objekt nicht verändern, ist eine gute Praxis. Dadurch wird deine Absicht dokumentiert, die Funktion kann mit const-Objekten arbeiten, und der Compiler kann versehentliche Änderungen erkennen. Jede Memberfunktion, die Daten nur liest, sollte als const gekennzeichnet werden.
Aufgabe
EinfachErstellen wir einen Temperaturkonverter, der zeigt, wann und warum const-Memberfunktionen verwendet werden. Du erstellst eine Klasse, deren einige Methoden Daten nur lesen (und const sein sollten), während andere den Zustand des Objekts ändern.
Du erstellst zwei Dateien, um deinen Code zu organisieren:
Temperature.h: Definiere eineTemperature-Klasse, die einen Temperaturwert speichert und verschiedene Möglichkeiten zum Lesen und Ändern dieses Werts bereitstellt. Deine Klasse sollte Folgendes enthalten:- Ein privates Member
celsius(double) zum Speichern der Temperatur - Einen Konstruktor, der einen anfänglichen Celsius-Wert übernimmt
- Eine
getCelsius()-Methode, die den gespeicherten Wert zurückgibt. Sie sollte const sein, da sie nur Daten liest - Eine
getFahrenheit()-Methode, die die Temperatur mithilfe der Formelcelsius * 9.0 / 5.0 + 32.0berechnet und zurückgibt; sie sollte ebenfalls const sein, da sie nichts ändert - Eine
getKelvin()-Methode, die die Temperatur mithilfe voncelsius + 273.15in Kelvin zurückgibt: ebenfalls const - Eine
setCelsius(double value)-Methode, die die gespeicherte Temperatur aktualisiert. Sie kann nicht const sein, da sie das Objekt ändert - Eine
adjustBy(double delta)-Methode, die delta zur aktuellen Temperatur addiert; auch sie ist nicht const
- Ein privates Member
main.cpp: Zeige, wie const-Memberfunktionen sowohl mit normalen als auch mit const-Objekten funktionieren. Lies zunächst einen Temperaturwert aus der Eingabe ein und:- Erstelle ein
Temperature-Objekt mit dem Eingabewert - Gib
"Initial: <celsius>C = <fahrenheit>F = <kelvin>K"aus - Verändere die Temperatur um
10.0Grad - Gib
"After adjustment: <celsius>C"aus - Erstelle eine Hilfsfunktion
void printReadings(const Temperature& temp), die eine const-Referenz übernimmt und"Reading: <celsius>C, <fahrenheit>F"ausgibt. Diese Funktion kann für temp nur const-Methoden aufrufen - Rufe
printReadings()mit deinem Temperaturobjekt auf - Setze die Temperatur auf
0.0(Gefrierpunkt) - Gib
"Freezing point: <celsius>C = <fahrenheit>F"aus
- Erstelle ein
Formatiere alle Temperaturwerte mit einer Nachkommastelle mithilfe von std::fixed und std::setprecision(1) aus <iomanip>.
Die wichtigste Erkenntnis hier ist, dass printReadings() eine const-Referenz erhält und daher nur als const markierte Methoden aufrufen kann. Deshalb ist es wichtig, deine Getter-Methoden korrekt als const zu markieren. Dadurch können sie in Situationen verwendet werden, in denen das Objekt nicht geändert werden darf.
Probier es selbst
#include <iostream>
#include <iomanip>
#include "Temperature.h"
using namespace std;
// TODO: Implementiere die Methoden der Temperature-Klasse hier
// Konstruktor
Temperature::Temperature(double initialCelsius) {
// TODO: Initialisiere celsius
}
// TODO: Implementiere getCelsius() als const
// TODO: Implementiere getFahrenheit() als const
// TODO: Implementiere getKelvin() als const
// TODO: Implementiere setCelsius(double value)
// TODO: Implementiere adjustBy(double delta)
// TODO: Erstelle eine Hilfsfunktion printReadings, die eine const Temperature& nimmt
// und "Reading: <celsius>C, <fahrenheit>F" ausgibt
// Note: Diese Funktion kann nur const-Methoden auf temp aufrufen!
int main() {
double initialTemp;
cin >> initialTemp;
// Ausgabeformatierung festlegen
cout << fixed << setprecision(1);
// TODO: Erstelle ein Temperature-Objekt mit dem Eingabewert
// TODO: Gib "Initial: <celsius>C = <fahrenheit>F = <kelvin>K" aus
// TODO: Passe die Temperatur um 10.0 Grad an
// TODO: Print "After adjustment: <celsius>C"
// TODO: Rufe printReadings() mit deinem Temperature-Objekt auf
// TODO: Set the temperature to 0.0 (freezing point)
// TODO: Print "Freezing point: <celsius>C = <fahrenheit>F"
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 & QuelldateienNamespaces & GültigkeitsbereichEinführung in OOP mit C++Klassen vs. ObjekteDer „this“-ZeigerMethoden (Member-Funktionen)Attribute (Datenmember)Grundlagen zu Ctors & DtorsRückblick – Einfacher Taschenrechner4Klassenattribute
Instanz- vs. statische MemberGetter und SetterConst-MemberfunktionenMutable-SchlüsselwortStatische Methoden und VariablenFriend-Funktionen und -KlassenZusammenfassung – Bankkontoverwaltung7Vererbung
Grundlagen der VererbungZugriffsebenen bei der VererbungAufrufreihenfolge von Ctor & DtorÜberschreiben von MethodenVirtuelle Funktionen & VTableMehrfachvererbungVirtuelle VererbungRückblick – Mitarbeiterhierarchie2Speicherverwaltung
Stack- vs. Heap-SpeicherZeiger und ReferenzenDynamischer Speicher (new/delete)Intelligente Zeiger in C++RAII in C++Rückblick – Dynamischer Array-Manager5Kapselung
Zugriffsbezeichner in C++Zugriffsbezeichner im DetailInformationsverbergungStruct vs. KlasseVerschachtelte und innere KlassenWiederholung – Studierendenverwaltungssystem8Polymorphie
Polymorphie zur Compilezeit vs. LaufzeitFunktionsüberladungVirtuelle Funktionen erneut betrachtetRein virtuelle FunktionenAbstrakte KlassenInterface-Design in C++Dynamic Casting & RTTIRückblick – Shape-Calculator3Konstruktoren & Destruktoren
StandardkonstruktorParametrisierter KonstruktorKopierkonstruktorMove-KonstruktorKonstruktor-InitialisierungslistenDelegierende KonstruktorenDestruktor im DetailDrei-/Fünf-/Null-RegelZusammenfassung – String-Klasse6Operatorüberladung
Einführung in die OperatorüberladungArithmetische OperatorüberladungVergleichsoperatorüberladungStream-OperatorenZuweisungsoperatorüberladungÜberladung der Operatoren [] und ()TypkonvertierungsoperatorenWiederholung – Matrix-Klasse9Templates
FunktionstemplatesKlassen-TemplatesTemplate-SpezialisierungVariadische TemplatesGrundlagen zu SFINAE und Type TraitsRückblick – Generischer ContainerÜbe selbstständig: Online-C++-Compiler