Menu
Coddy logo textTech

Константные функции-члены

Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy. Урок 29 из 104.

В предыдущем уроке ты видел ключевое слово const в методах-геттерах. Но что именно означает, когда const появляется после списка параметров функции? const member function обещает не изменять переменные-члены объекта.

class Rectangle {
    int width;
    int height;
public:
    Rectangle(int w, int h) : width(w), height(h) {}
    
    int getArea() const {      // const функция-член
        return width * height;  // Чтение членов разрешено
    }
    
    void setWidth(int w) {     // Non-const - изменяет объект
        width = w;
    }
};

const после списка параметров сообщает компилятору: «Эта function не изменит состояние объекта». Если попытаться изменить переменную-член внутри const function, компилятор выдаст ошибку.

Это становится особенно важно при работе с объектами const или ссылками const. Объект const может вызывать только const member function:

void printArea(const Rectangle& rect) {
    std::cout << rect.getArea();    // OK - getArea() является const
    // rect.setWidth(10);           // ERROR - setWidth() не является const
}

Помечать функции как const, если они не изменяют объект, — хорошая практика. Это документирует ваше намерение, позволяет функции работать с объектами const и помогает компилятору обнаруживать случайные изменения. Любую member-функцию, которая только считывает данные, следует помечать как const.

challenge icon

Задание

Легко

Создадим конвертер температуры, демонстрирующий, когда и зачем использовать const member functions. Ты создашь класс, в котором одни методы только читают данные (и должны быть const), а другие изменяют состояние объекта.

Ты создашь два файла, чтобы организовать свой код:

  • Temperature.h: определи класс Temperature, который хранит значение температуры и предоставляет различные способы его чтения и изменения. В твоём классе должны быть:
    • Приватный member celsius (double) для хранения температуры
    • Constructor, принимающий Initial значение по шкале Цельсия
    • Метод getCelsius(), возвращающий сохранённое значение. Он должен быть const, поскольку только читает данные
    • Метод getFahrenheit(), вычисляющий и возвращающий температуру по шкале Фаренгейта с использованием Formula celsius * 9.0 / 5.0 + 32.0; он также должен быть const, поскольку ничего не изменяет
    • Метод getKelvin(), возвращающий температуру по шкале Кельвина с использованием celsius + 273.15; он также должен быть const
    • Метод setCelsius(double value), обновляющий сохранённую температуру. Он не может быть const, поскольку изменяет объект
    • Метод adjustBy(double delta), добавляющий delta к текущей температуре; он также не должен быть const
  • main.cpp: продемонстрируй, как работают const member functions с обычными и const объектами. Считай Initial значение температуры из input, затем:
    • Create объект Temperature с введённым значением
    • Выведи "Initial: <celsius>C = <fahrenheit>F = <kelvin>K"
    • Увеличь температуру на 10.0 degrees
    • Выведи "After adjustment: <celsius>C"
    • Создай функцию-помощник void printReadings(const Temperature& temp), которая принимает const ссылку и выводит "Reading: <celsius>C, <fahrenheit>F". Эта функция может вызывать для temp только const методы
    • Вызови printReadings() со своим объектом температуры
    • Установи температуру равной 0.0 (точка Freezing)
    • Выведи "Freezing point: <celsius>C = <fahrenheit>F"

Форматируй все значения температуры с одним десятичным знаком, используя std::fixed и std::setprecision(1) из <iomanip>.

Ключевая идея заключается в том, что printReadings() получает const ссылку, поэтому может вызывать только методы, помеченные как const. Именно поэтому важно правильно помечать методы доступа как const. Это позволяет им работать в контекстах, где объект нельзя изменить.

Попробуйте сами

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

// TODO: Реализуйте методы класса Temperature здесь
// Конструктор
Temperature::Temperature(double initialCelsius) {
    // TODO: Инициализируйте celsius
}

// TODO: Реализуйте getCelsius() как const

// TODO: Реализуйте getFahrenheit() как const

// TODO: Реализуйте getKelvin() как const

// TODO: Реализуйте setCelsius(double value)

// TODO: Реализуйте adjustBy(double delta)


// TODO: Создайте вспомогательную функцию printReadings, которая принимает const Temperature& 
// и выводит "Reading: <celsius>C, <fahrenheit>F"
// Note: Эта функция может вызывать только const-методы у temp!


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

    // Установите форматирование вывода
    cout << fixed << setprecision(1);

    // TODO: Создайте объект Temperature с входным значением

    // TODO: Выведите "Initial: <celsius>C = <fahrenheit>F = <kelvin>K"

    // TODO: Измените температуру на 10.0 градусов

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

    // TODO: Вызовите printReadings() с вашим объектом Temperature

    // TODO: Set the temperature to 0.0 (freezing point)

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

    return 0;
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор C++