Re[6]: const - когда быть, когда не быть
От: Дмитро  
Дата: 24.04.03 10:52
Оценка: 10 (1) -1
Здравствуйте, jazzer, Вы писали:

J>вот всякие кеширования и прочие временные и вспомогательные радости стоит объявлять mutable, ибо они не определяют состояние объекта, и, соответственно, не влияют на его константность. А дескриптор сокета, открытого временно и по случаю, не определяет состояние объекта, посему должен быть mutable.


Пример. Допустим, мы разрабатываем класс, в котором хранятся параметры чего-либо. Каждый параметр имеет свой геттер (например, значение параметра value1 можно получить вызвав getValue1). Параметры могут, например, загружаться их файла.

Вот прямолинейная реализация. Параметры загружаются сразу в момент создания объекта.
class Settings {
private:
     int m_value1;
     int m_value2;
     int m_value3;
     int m_value4;
// . . .

     void loadFromFile();
public:
     Settings() {
          loadFromFile();
     }
     int getValue1() const {
          return m_value1;
     }
// . . .
};


Вот реализация с отложенной загрузкой. Параметры загружаются только тогда, когда в них возникает необходимость.
class Settings {
private:
     bool mutable m_bLoaded;
     int mutable m_value1;
     int mutable m_value2;
     int mutable m_value3;
     int mutable m_value4;
// . . .

     // здесь const фиктивный. он нужен для того,
     // чтобы мог вызываться из константных методов
     void loadFromFile() const;
public:
     Settings(): m_bLoaded(false) {
     }
     int getValue1() const {
          if(!m_bLoaded)
               loadFromFile();
          return m_value1;
     }
// . . .
};

Члены-данные m_value1, m_value2 и прочее были объявлены mutable для того, чтобы в них можно было загрузить значения внутри геттера.

Разве во второй реализации члены-данные m_value1, m_value2 и прочее не относятся к состоянию объекта? Что тогда к состоянию объекта этого класса относится?


J>состояние объекта — это тоже деталь его интерфейса, хоть и не оформленная в виде метода.

J>И если какой-то метод не должен менять состояние объекта, то это должно быть прописано в прототипе этого метода.
J>А то, как это все устроено внутри объекта, не имеет никакого отношения к его интерфейсу вообще, и к константности методов, в частности.

Модификтор const, на мой взгляд, играет две роли. Первая, он выполняет роль некого дискриминанта в интерфейсе класса. Он как бы в общем интерфейсе выделяет подинтерфейс, состоящий только их константных методов, которые не меняют состояние объекта. Вторая, он является указанием компилятору, чтобы тот предотвращал изменения членов-данных внутри константных методов. Как правило, изменение членов-данных приводит к изменению состояния объекта. В этом случае, эти две роли, являются взаимодополняющими. Однако члены-данные -- это не состояние. Они определяют его, но не являются им. Для класса "рациональных чисел" "две третьих" и "четыре шестых" -- может быть одним и тем же состоянием, пользователь класса может не иметь возможность в принципе их различать. Так же как и для "класса плоских углов меньших 360 градусов" 50 градусов и 410 -- это одно и тоже, хотя представлены они по разному. В недрах класса одно представление может переходить в другое (рациональное число может сокращаться, а угол приводиться к определенным пределам) не меняя при этом состояние объекта. А компилятор об этом не знает, в потому и ругается. А вместе с ним, ругается и разработчик класса, который ставит mutable или прибегает к иным приемам только для того, чтобы успокоить компилятор.


Обсуждение этой темы как мне кажется, склонно перерасти в религиозную войну. Наверное, не может быть однозначного ответа, когда нужно ставить const, а когда нет. Решение, которое для одного является образцом совершенства, для другого может показаться уродливым и некрасивым. И наоборот. Я не думаю, что что-то сможет меня быстро переубедить. Равно как, далек от мысли, что я кого-то переубедил. Но в любом случае, готов выслушать любые мнения.

--
Дмитрий
--
Дмитрий
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.