Re[2]: const - когда быть, когда не быть
От: Дмитро  
Дата: 23.04.03 12:10
Оценка: 11 (2) -5
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, Аноним, Вы писали:


А>довольно продолжительное время ломаю голову — когда делать функцию константной, а когда в этом нет необходимости???


А>объясните человеческим языком, пожалста.

WH>Если она не должна менять обьект то она должна быть константной.

На самом-то деле вопрос гораздо сложнее, чем кажется. Бездумное использование этого модификатора (всовывание его всюду, где только можно), способно создать немало неприятностей.

Пример. Допустим, у нас есть некий класс A, от которого в принцие можно наследоваться (т.е. не final и не sealed), с методом doSomething. Реализация этого метода в этом же классе не меняет члены данных. Стоит ли объявить ее const? Предположим, мы так и сделали.
class A {
private:
   int i;
public:
   virtual void doSomething() const {
      printf("%d\n", i);
   }
};

Пока все замечательно. Далее пишется отпределенное количество кода, где ссылка на объект класса A в другие методы и функции, в которых нужно всего лишь вызвать метод doSomething, передается как константная. Компилятор честно за этим следит и ненавязчиво подсказывает если что. В общем, хорошо.

И вдруг, нам понадобилось создать класс B унаследованный от A и переопределить в нем doSomething. И тут оказывается, что B::doSomething меняет члены данных класса B, поэтому не может быть константным!

Можно воспользоваться последними достижениями прогрессивного человечества -- модификатором mutable и объявить с его помощью все члены-данные, которые меняются в методе B::doSomething (а заодно и члены-данные, которые меняются и в других "константных" методах). При этом наблюдается странная картина, мы сознательно избавляемся от тех благ, которые сулил const! Зачем тогда надо было его городить?
class B: public A {
private:
   int mutable j;
public:
   virtual void doSomething() const {
      j += i; // меняется член-данное
      printf("%d\n", i);
   }
};


Можно пойти другим путем и изменить интерфейс базового класса (убрать const из объявления A::doSomething). А это, как правило, означает, что надо заставить компилироваться некое количество кода, которое было написано до этого.

Поэтому, я считаю, что если есть хоть какое-то сомнение в необходимости constа, что лучше его не использовать.

Исходя из своего опыта, могу сказать, что в большинстве случаев:

1. const никогда не следует использовать в объявлении методов интерфейсных классов. Модификатор const в данном случае навязывает разработчику классов (наследующихся от заданных интерфейсных) некое внутреннее представление и, как следствие, нарушает инкапсуляцию.

2. const следует использовать в объявлении копи-конструкторов, операторов присваивания, различного рода операторов сравнения и прочих операторов, в которых по смыслу необходима константность объекта. Так же во вспомагательных методах, которые должны вызываться их этих операторов и таких же вспомагательных методов, должны быть константными. Как правило, такие классы относительно простые, и имеют очевидное внутреннее представление, которое не будет радикально меняться.

3. const следует использовать при передаче строк в качестве параметра (char const * или const char *)

4. const желательно использовать при объявлении членов-данных, которые не должны меняться на протяжении всей жизни объекта.

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