Menu
Coddy logo textTech

Funzioni membro const

Fa parte della sezione Programmazione orientata agli oggetti del percorso C++ di Coddy. Lezione 29 di 104.

Hai visto la parola chiave const nei metodi getter nella lezione precedente. Ma cosa significa esattamente quando const compare dopo l’elenco dei parametri di una funzione? Una funzione membro const promette di non modificare alcuna variabile membro dell’oggetto.

class Rectangle {
    int width;
    int height;
public:
    Rectangle(int w, int h) : width(w), height(h) {}
    
    int getArea() const {      // funzione membro const
        return width * height;  // È consentito leggere i membri
    }
    
    void setWidth(int w) {     // Non const - modifica l'oggetto
        width = w;
    }
};

Il const dopo l'elenco dei parametri comunica al compilatore: "Questa funzione non modificherà lo stato dell'oggetto." Se provi a modificare una variabile membro all'interno di una funzione const, il compilatore genererà un errore.

Questo diventa essenziale quando si lavora con oggetti const o riferimenti const. Un oggetto const può chiamare solo funzioni membro const:

void printArea(const Rectangle& rect) {
    std::cout << rect.getArea();    // OK - getArea() è const
    // rect.setWidth(10);           // ERROR - setWidth() non è const
}

Contrassegnare come const le funzioni che non modificano l'oggetto è una buona pratica. Documenta le tue intenzioni, consente alla funzione di lavorare con oggetti const e aiuta il compilatore a rilevare modifiche accidentali. Qualsiasi funzione membro che si limita a leggere i dati dovrebbe essere contrassegnata come const.

challenge icon

Sfida

Facile

Costruiamo un convertitore di temperature che mostra quando e perché usare le funzioni membro const. Creerai una classe in cui alcuni metodi leggono soltanto i dati (e dovrebbero essere const), mentre altri modificano lo stato dell'oggetto.

Creerai due file per organizzare il codice:

  • Temperature.h: definisci una classe Temperature che memorizza un valore di temperatura e offre diversi modi per leggerlo e modificarlo. La classe dovrebbe avere:
    • Un membro privato celsius (double) per memorizzare la temperatura
    • Un costruttore che accetta un valore iniziale in Celsius
    • Un metodo getCelsius() che restituisce il valore memorizzato. Dovrebbe essere const, dato che legge soltanto i dati
    • Un metodo getFahrenheit() che calcola e restituisce la temperatura in Fahrenheit usando la formula celsius * 9.0 / 5.0 + 32.0, anch'esso const perché non modifica nulla
    • Un metodo getKelvin() che restituisce la temperatura in Kelvin usando celsius + 273.15: anche questo const
    • Un metodo setCelsius(double value) che aggiorna la temperatura memorizzata. Non può essere const perché modifica l'oggetto
    • Un metodo adjustBy(double delta) che aggiunge il delta alla temperatura corrente, anch'esso non const
  • main.cpp: mostra come funzionano le funzioni membro const sia con oggetti normali sia con oggetti const. Leggi un valore iniziale della temperatura dall'input, poi:
    • Crea un oggetto Temperature con il valore di input
    • Stampa "Initial: <celsius>C = <fahrenheit>F = <kelvin>K"
    • Regola la temperatura di 10.0 gradi
    • Stampa "After adjustment: <celsius>C"
    • Crea una funzione di supporto void printReadings(const Temperature& temp) che accetta un riferimento const e stampa "Reading: <celsius>C, <fahrenheit>F". Questa funzione può chiamare soltanto metodi const su temp
    • Chiama printReadings() passando il tuo oggetto temperatura
    • Imposta la temperatura a 0.0 (punto di congelamento)
    • Stampa "Freezing point: <celsius>C = <fahrenheit>F"

Formatta tutti i valori di temperatura con una cifra decimale usando std::fixed e std::setprecision(1) da <iomanip>.

L'idea fondamentale è che printReadings() riceve un riferimento const, quindi può chiamare soltanto metodi contrassegnati come const. Ecco perché è importante contrassegnare correttamente come const i metodi getter. In questo modo possono essere usati in contesti in cui l'oggetto non può essere modificato.

Provalo tu

#include <iostream>
#include <iomanip>
#include "Temperature.h"
using namespace std;

// TODO: Implementa qui i metodi della classe Temperature
// Costruttore
Temperature::Temperature(double initialCelsius) {
    // TODO: Inizializza celsius
}

// TODO: Implementa getCelsius() come const

// TODO: Implementa getFahrenheit() come const

// TODO: Implementa getKelvin() come const

// TODO: Implementa setCelsius(double value)

// TODO: Implementa adjustBy(double delta)


// TODO: Crea una funzione di supporto printReadings che accetti un const Temperature& 
// e stampi "Reading: <celsius>C, <fahrenheit>F"
// Nota: questa funzione può chiamare solo metodi const su temp!


int main() {
    double initialTemp;
    cin >> initialTemp;

    // Imposta la formattazione dell'output
    cout << fixed << setprecision(1);

    // TODO: Crea un oggetto Temperature con il valore di input

    // TODO: Stampa "Initial: <celsius>C = <fahrenheit>F = <kelvin>K"

    // TODO: Regola la temperatura di 10.0 gradi

    // TODO: Stampa "After adjustment: <celsius>C"

    // TODO: Chiama printReadings() con il tuo oggetto Temperature

    // TODO: Imposta la temperatura a 0.0 (punto di congelamento)

    // TODO: Stampa "Freezing point: <celsius>C = <fahrenheit>F"

    return 0;
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore C++ online