Fonctions membres const
Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy — leçon 29 sur 104.
Vous avez vu le mot-clé const sur les méthodes getter dans la leçon précédente. Mais que signifie exactement const lorsqu'il apparaît après la liste des paramètres d'une fonction ? Une fonction membre const promet de ne modifier aucune variable membre de l'objet.
class Rectangle {
int width;
int height;
public:
Rectangle(int w, int h) : width(w), height(h) {}
int getArea() const { // fonction membre constante
return width * height; // La lecture des membres est autorisée
}
void setWidth(int w) { // Non-const - modifie l'objet
width = w;
}
};Le mot-clé const après la liste des paramètres indique au compilateur : « Cette fonction ne modifiera pas l'état de l'objet. » Si vous essayez de modifier une variable membre à l'intérieur d'une fonction const, le compilateur générera une erreur.
Cela devient essentiel lorsqu'on travaille avec des objets const ou des références const. Un objet const ne peut appeler que des fonctions membres const :
void printArea(const Rectangle& rect) {
std::cout << rect.getArea(); // OK - getArea() est const
// rect.setWidth(10); // ERREUR - setWidth() n'est pas const
}Marquer les fonctions comme const lorsqu'elles ne modifient pas l'objet est une bonne pratique. Cela documente votre intention, permet à la fonction de fonctionner avec des objets const, et aide le compilateur à détecter les modifications accidentelles. Toute fonction membre qui ne fait que lire des données devrait être marquée const.
Défi
FacileConstruisons un convertisseur de température qui démontre quand et pourquoi utiliser des fonctions membres const. Vous allez créer une classe où certaines méthodes ne font que lire des données (et devraient être const) tandis que d'autres modifient l'état de l'objet.
Vous allez créer deux fichiers pour organiser votre code :
Temperature.h: Définissez une classeTemperaturequi stocke une valeur de température et fournit diverses manières de la lire et de la modifier. Votre classe doit avoir :- Un membre privé
celsius(double) pour stocker la température - Un constructeur qui prend une valeur Celsius initiale
- Une méthode
getCelsius()qui retourne la valeur stockée — celle-ci doit être const puisqu'elle ne fait que lire des données - Une méthode
getFahrenheit()qui calcule et retourne la température en Fahrenheit en utilisant la formulecelsius * 9.0 / 5.0 + 32.0— également const puisqu'elle ne modifie rien - Une méthode
getKelvin()qui retourne la température en Kelvin en utilisantcelsius + 273.15— const également - Une méthode
setCelsius(double value)qui met à jour la température stockée — celle-ci ne peut pas être const puisqu'elle modifie l'objet - Une méthode
adjustBy(double delta)qui ajoute le delta à la température actuelle — également non-const
- Un membre privé
main.cpp: Démontrez comment les fonctions membres const fonctionnent avec des objets réguliers et des objets const. Lisez une valeur de température initiale à partir de l'entrée, puis :- Créez un objet
Temperatureavec la valeur d'entrée - Affichez
"Initial: <celsius>C = <fahrenheit>F = <kelvin>K" - Ajustez la température de
10.0degrés - Affichez
"After adjustment: <celsius>C" - Créez une fonction auxiliaire
void printReadings(const Temperature& temp)qui prend une référence const et affiche"Reading: <celsius>C, <fahrenheit>F"— cette fonction ne peut appeler que des méthodes const sur temp - Appelez
printReadings()avec votre objet de température - Réglez la température à
0.0(point de congélation) - Affichez
"Freezing point: <celsius>C = <fahrenheit>F"
- Créez un objet
Formatez toutes les valeurs de température avec une décimale en utilisant std::fixed et std::setprecision(1) de <iomanip>.
L'idée clé ici est que printReadings() reçoit une référence const, elle ne peut donc appeler que des méthodes marquées comme const. C'est pourquoi il est important de marquer correctement vos méthodes "getter" comme const — cela leur permet de fonctionner dans des contextes où l'objet ne peut pas être modifié.
Aide-mémoire
Une fonction membre const promet de ne modifier aucune variable membre de l'objet. Le mot-clé const est placé après la liste des paramètres de la fonction :
class Rectangle {
int width;
int height;
public:
int getArea() const { // fonction membre const
return width * height; // La lecture des membres est autorisée
}
void setWidth(int w) { // Non-const - modifie l'objet
width = w;
}
};Les fonctions membres const peuvent uniquement lire les variables membres, pas les modifier. Si vous essayez de modifier une variable membre à l'intérieur d'une fonction const, le compilateur produira une erreur.
Un objet const ou une référence const ne peut appeler que des fonctions membres const :
void printArea(const Rectangle& rect) {
std::cout << rect.getArea(); // OK - getArea() est const
// rect.setWidth(10); // ERREUR - setWidth() n'est pas const
}Marquez les fonctions comme const lorsqu'elles ne modifient pas l'objet. Cela documente votre intention, permet à la fonction de travailler avec des objets const et aide le compilateur à détecter les modifications accidentelles. Toute fonction membre qui ne fait que lire des données devrait être marquée const.
Essayez vous-même
#include <iostream>
#include <iomanip>
#include "Temperature.h"
using namespace std;
// TODO: Implémenter les méthodes de la classe Temperature ici
// Constructeur
Temperature::Temperature(double initialCelsius) {
// TODO: Initialiser celsius
}
// TODO: Implémenter getCelsius() en tant que const
// TODO: Implémenter getFahrenheit() en tant que const
// TODO: Implémenter getKelvin() en tant que const
// TODO: Implémenter setCelsius(double value)
// TODO: Implémenter adjustBy(double delta)
// TODO: Créer une fonction auxiliaire printReadings qui prend un const Temperature&
// et affiche "Reading: <celsius>C, <fahrenheit>F"
// Note: Cette fonction ne peut appeler que des méthodes const sur temp !
int main() {
double initialTemp;
cin >> initialTemp;
// Définir le formatage de la sortie
cout << fixed << setprecision(1);
// TODO: Créer un objet Temperature avec la valeur d'entrée
// TODO: Afficher "Initial: <celsius>C = <fahrenheit>F = <kelvin>K"
// TODO: Ajuster la température de 10.0 degrés
// TODO: Afficher "After adjustment: <celsius>C"
// TODO: Appeler printReadings() avec votre objet temperature
// TODO: Régler la température à 0.0 (point de congélation)
// TODO: Afficher "Freezing point: <celsius>C = <fahrenheit>F"
return 0;
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Fondamentaux de la POO
Fichiers externesBuild et Compilation C++Fichiers d'en-tête et Fichiers sourceEspaces de noms et PortéeIntroduction à la POO en C++Classes vs ObjetsLe pointeur 'this'Méthodes (Fonctions membres)Attributs (Membres de données)Bases des Ctors et DtorsRécapitulatif - Calculatrice simple4Propriétés de classe
Membres d'instance vs membres statiquesGetters et SettersFonctions membres constMot-clé mutableMéthodes et variables statiquesFonctions et classes amiesRécapitulatif - Gestionnaire de compte bancaire7Héritage
Héritage de baseNiveaux d'accès à l'héritageOrdre d'appel des Ctor et DtorRedéfinition de méthodesFonctions virtuelles et VTableHéritage multipleHéritage virtuelRécapitulatif - Hiérarchie des employés10Présentation de la STL
Présentation et philosophie de la STLConteneurs de la STLItérateursAlgorithmes de la STLFoncteurs et expressions lambdaRécapitulatif - Fréquence des mots13Patrons de conception, Partie 1
Introduction aux patrons de conceptionPatron SingletonFabrique & Fabrique abstraitePatron MonteurPatron ObservateurPatron Stratégie2Gestion de la mémoire
Mémoire Pile vs TasPointeurs et RéférencesMémoire dynamique (new/delete)Smart Pointers en C++RAII en C++Récapitulatif - Gestionnaire de tableaux dynamiques5Encapsulation
Spécificateurs d'accès en C++Spécificateurs d'accès en profondeurMasquage d'informationStruct vs ClassClasses imbriquées et internesRécapitulatif - Système de gestion d'étudiants8Polymorphisme
Polymorphisme : Compilation vs ExécutionSurcharge de fonctionsRetour sur les fonctions virtuellesFonctions virtuelles puresClasses abstraitesConception d'interfaces en C++Dynamic Casting & RTTIRécapitulatif - Calculateur de formes11Concepts avancés de la POO
Composition vs HéritageMixins via CRTPIdiome PimplEffacement de typeEnum Classes & Typage fortGestion des exceptions en POOHiérarchies d'exceptions personnalisées14Patrons de conception, Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Template MethodPatron ÉtatPatron CompositeRAII en tant que patron3Constructeurs et Destructeurs
Constructeur par défautConstructeur paramétréConstructeur de copieConstructeur de déplacementListes d'initialisation du constructeurConstructeurs déléguésAnalyse approfondie du destructeurRègle de trois / cinq / zéroRécapitulatif - Classe String6Surcharge d'opérateurs
Introduction à la surcharge d'opérateursSurcharge des opérateurs arithmétiquesSurcharge des opérateurs de comparaisonOpérateurs de fluxSurcharge de l'opérateur d'affectationSurcharge des opérateurs [] et ()Opérateurs de conversion de typeRécapitulatif - Classe Matrix9Templates
Templates de fonctionsTemplates de classesSpécialisation de templatesTemplates variadiquesBases de SFINAE & Type TraitsRécapitulatif - Conteneur générique