12 июня 2012

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


... или «...обещаю, для тебя — никакой разницы. Ничего не изменится...»


Простое правило: если логическое состояние объекта после выполнения метода останется неизменным, то смело объявляйте его (метод) константным, а физически изменяющиеся переменные-члены класса объявляйте со спецификатором mutable.
Кстати, mutable можно применять только к нестатическим переменным-членам, что логично.
Для клиента класса не важно, изменили ли вы какую-нибудь переменную, которая для него ничего не значит. Для него важно, чтобы объект был тем же, чем был до этого, с логической точки зрения. И так, ещё раз: всегда предпочитайте физической константности логическую. И выбросьте из головы, что применение mutable — признак непрофессиональности. Это ложное наставление неопытных и глупых программистов. Все признанные мастера советуют и рекомендуют пользоваться mutable. Пример дальше.
...

В этом примере описан класс, содержащий метод, возвращающий какое-то целочисленное значение. Представим, что это целочисленное значение вычисляется очень сложным и ресурсоёмким методом. Потому, вычисление этого значения не выполняется при инициализации объекта, а только по запросу (отложенное вычисление):
class AverageFoodConsumption final {
public:
  int getAverage() const {
    if (!calculated_) {
      avg_ = calculateAverage();
      calculated_ = true;
    }
    return avg_;
  }

private:
  int calculateAverage() const {
    // Открыть Базу данных или файл, рассчитать
    // различные типы пищи, её потребление, высчитать
    // какой-то общий коэффициент и вернуть его.
  }

private:
  mutable bool calculated_;
  mutable int  avg_;
};


Метод getAverage объявлен константным. Обе переменные, объявленные в классе, в нём модифицируются, потому их мы объявляем, используя спецификатор mutable. Объект вычисляет требуемое от него значение во время первого запроса. И всё — в дальнейшем целочисленное значение просто возвращается.