Урок 123. Классы и const

   ⁄ 

 Обновлено 10 Мар 2018  ⁄ 

⁄   1115

В 37 уроке мы узнали, что фундаментальные типы данных (int, double, char и т.д.) можно сделать константными, используя ключевое слово const, и что все константные переменные должны быть инициализированы во время объявления.

В случае с константными фундаментальными типами данных инициализация может быть копирующей, прямой или uniform:

Константные объекты классов

Аналогично объекты классов можно сделать константными (через ключевое слово const). Инициализация выполняется через конструкторы классов:

Как только константный объект класса инициализируется через конструктор, любая попытка изменить переменные-члены объекта запрещена, так как это нарушает принципы константности объекта. Запрещается как изменение переменных-членов напрямую (если они являются public), так и вызов методов (сеттеров), с помощью которых можно установить значения переменных-членов. Рассмотрим следующий класс:

Строчки 16 и 17 вызовут ошибки компилятора, так как они нарушают принципы константности объекта, пытаясь напрямую изменить переменную-член, и вызывая сеттер для изменения значения переменной-члена.

Константные методы классов

Теперь рассмотрим следующую строчку кода:

Удивительно, но это также вызовет ошибку компиляции, хотя getValue() не делает ничего для изменения переменной-члена! Оказывается, константные объекты класса могут явно вызывать только константные методы класса, а getValue() не указан как константный метод. Константный метод – это метод, который гарантирует, что не будет изменять объект или вызывать неконстантные методы класса (поскольку они могут изменить объект).

Чтобы сделать getValue() константным, нужно просто добавить ключевое слово const к прототипу функции после списка параметров, но перед телом функции:

Теперь getValue() является константным методом, что означает, что мы можем вызывать его через любой константный объект.

Для методов, определенных вне класса, ключевое слово const должно использоваться как в прототипе функции в теле класса, так и в определении функции:

Кроме того, любой константный метод, который пытается изменить переменную-член или вызвать неконстантный метод класса также приведет к ошибке компилятора. Например:

В этом примере resetValue() был установлен константным, но он пытается изменить значение m_value. Это вызовет ошибку компилятора.



Обратите внимание, конструкторы не могут быть константными. Это связано с тем, что они должны иметь возможность инициализировать переменные-члены класса, а константный конструктор этого не сможет сделать. Следовательно, в С++ константные конструкторы запрещены.

Стоит отметить, что константный объект класса может вызывать конструктор, который будет инициализировать все, некоторые или ни одну из переменных-членов!

Правило: Делайте все ваши методы, которые не изменяют данные объекта класса, константными.

Константные ссылки и классы

Еще одним способом создания константных объектов является передача объекта в функцию по константной ссылке.

В уроке о передаче аргументов по ссылке, мы рассмотрели преимущества передачи аргументов по константной ссылке, нежели по значению. Вкратце: передача аргументов по значению создает копию значения (что является медленным) — большую часть времени нам не нужна копия, а ссылка уже указывает на исходный аргумент и является более эффективным, так как избегает создания и использование ненужной копии. Мы обычно делаем ссылку константной для гарантии того, что функция не изменит непреднамеренно значение аргумента и позволит функции работать с r-values (например, литералами).

Можете ли вы определить, что не так в следующем коде?

Ответ заключается в том, что внутри функции printDate(), объект date рассматривается как константный. И через этот константный date мы вызываем функции getDay(), getMonth() и getYear(), которые являются неконстантными. Поскольку мы не можем вызывать неконстантные методы через константные объекты, то здесь мы получим ошибку компиляции.

Решение простое: сделать getDay(), getMonth() и getYear() константными:

Теперь в функции printDate() константный date сможет вызывать getDay(), getMonth() и getYear().

Перегрузка константных и неконстантных функций

Хотя это делается не очень часто, но функцию можно перегрузить таким образом, чтобы иметь константную и неконстантную версию одной и той же функции:

Константная версия функции будет вызываться для константных объектов, а неконстантная версия будет вызываться для неконстантных объектов:

Перегрузка метода и разделение его на константную и неконстантную версии обычно выполняется, когда возвращаемое значение должно различаться по константности (когда требуется константа, а когда нет). В примере выше неконстантная версия getValue() будет работать только с неконстантными объектами, но эта версия более гибкая, так как мы можем использовать её как для чтения, так и для записи m_value (что мы и делаем, присваивая строку «Hello!»).

Но когда мы не изменяем данные объекта класса, то тогда вызывается константная версия getValue().

Итого

Любой метод, который не изменяет данные объекта класса, должен быть const!

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (4 оценок, среднее: 5,00 из 5)
Загрузка...
Подписаться на обновления:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

ПОДПИСЫВАЙТЕСЬ

НА КАНАЛ RAVESLI В TELEGRAM

@ravesli

ПОДПИСАТЬСЯ БЕСПЛАТНО