Здравствуйте, 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 желательно использовать при объявлении членов-данных, которые не должны меняться на протяжении всей жизни объекта.
--
Дмитрий