Re: ИМХА про константность
От: Erop Россия  
Дата: 04.09.07 13:40
Оценка: 96 (9) +2
Здравствуйте, Аноним, Вы писали:

А>Во многих учебниках встречался с утверждениями типа "константный обьект класса изменить невозможно",..


Я не знаток и не учебник, но попробую поделиться некоторыми соображениями по вопросу.
Общий смысл понятия константность сводится к тому, что мы заявляем, что некое "значение" объекта не может измениться.
Тут возникает вопрос, что такое "значение". Это собственно то, что объект представляет. Если объект представляет число -- значит "значение" -- это число. Например объект "рациональное число" в состояниях {1 / 2 } и в состоянии { 2 / 4 } представляет одно и то же "значение" 0.5.
Объект "строка" представляет значение "последовательность символов", при этом где именно хранится эта последовательность символов и как в "значение" строки не входит.
Я не хочу углубляться в понятие "значение" объекта, так как это уведёт очень далеко от понятия константонсти.
Главное понимать, что в состоянии объекта есть как бы две грани. Одна -- это подробности реализации, которые пользователю объекта не интересны и некое "значение", ради которого объект собственно и используется.
Во всяком случае так обстоят дела в хороших программах.

Так вот, часто так бывает, что при программировании полезно указать, что "значение" какого-то объекта не может измениться в течении работы какого-то алгоритма.
Тогда этот объект изнутри этого алгоритма представляют как константный. При этом у константного объекта можно вызывать только константные методы.
Это просто некий сервис, предоставляемый языком.
Если ты обозначил какой-то метод константным, то ты сообщаешь пользователю класса, что этот метод не меняет "значение" класса.

В принципе, за одним небольшим исключением, ты волен реализовывать константность метода (то есть неизменность "значения" объекта) как тебе наравится. Но для удобства, C++ предлагет некоторую модель константности, которая обычно интуитивно понятна почти во всём.

Идея модели очень простая. Все поля и базы константного объекта -- константны.
Тут есть две тонкости.
Тонкость 1 состоит в том, что если такое константное поле является указателем, то менять нельзя сам указатель (например нельзя начать ссылаться на другой объект), а вот сам указуемый объект менять как раз можно. При этом довольно часто в "значение" объемлещего класса входит не "значение" указателя, а "значение" указуемого объекта.
Так что заботу о сохранении семантики константности С++ в случае поля-указаетля перекладывает на программиста.
Тонкость 2 состоит в том, что в объекте может быть поле "значение" которого не входит в "значение" объекта.
То есть вполне законно можно менять "значение" такого поля даже из константного (то есть не меняющего "значение" объекта) метода. Для этого в C++ есть ключевое слово mutable, которым маркируются такие поля.

При учёте этих двух тонкостей ситуация становится уже почти радужной, но только до той поры, пока ты пользуешься совсем простыми моделями константности методов. Если же тебе зачем-то потребуется что-то "непростое", то уже станет тесно.
Например, если константность метода будет зависеть от "значения" его параметров, то С++ модель константности становится совсем уж обременительной.

Именно для таких случаев и используется const_cast, по идее.
То есть может быть написано что-то типа (MFC-style):
class CMyClass {
public:
    Save( CArchive& arc ) const 
        { assert( arc.IsStoring(); const_cast<CMyClass *>( this )->Serialize( arc ); }
    Load( CArchive& arc ) 
        { assert( arc.IsLoading(); Serialize( arc ); }
protected:
    virtual Serialize( CArchive& );  // Тут собственно реализация сидит
};


Ну а теперь настало время вернуться к тому самом "одному небольшому исключению".
Исключние наступает в случае, когда на сцену выступают константные объекты стандартных типов (числа, указатели и т. п.). Так как неизменность их "значений" реализует и гарантирует компилятор, то он может использовать информацию о их константности для оптимизации и реализации этих объектов и работы с ними. Поэтому, если ты что-то говоришь о константности каких-то объектов, то в конце концов ты обычно что-то говоришь о константоности находящихся в них в виде явных или неявных полей объектов стандартных типов. И если ты тут будешь слишком вольно обращаться с константностью, то ты можешь нарваться.
Это всего лишь вопрос в том как ограничить произвол программиста и компилятора в области обращения с константностью стандартных типов. В С++ принято следующее компромиссное соглашение на эту тему.
Константность бывает как бы " истинная" и "предписанная".
Истинной константой является переменная, которую создали как константу. Если это переменная стандартного типа, то компилятор может с ней вытворять много странного, скажем может её вообще не заводить, пока ты не используешь её адрес, а использовать всюду непосредственно её "значение", а может завести в read-only сегменте памяти и отмапировать её значение прямо из секции данных исполняемого файла, а может и ещё чего учудить.
Если это поле какой-то структуры с "истинной" константностью, то компилятор всё равно может хаккерить, хотя и меньше. Во всякмо случае не использовать значение реально расположенное в памяти, и расположить в read-only памяти может запросто. Короче говоря в отношении работы с "истинными констанатми" у компилятора есть дополнительные степени свободы. Правда эта свобода не распространяется на mutable поля даже "истинных констант".
В отличии от "истинной" константности, есть ещё и константность "предписанная". Она возникает, когда мы начинаем обращаться с неконстантным объектом, как с константным. Например имея к нему доступ через константную ссылку. Тогда руки у компилятора связаны и мы можем как угодно мухлевать с const_cast, не рискуя нарваться на последствия "излишней изобретательности" компилятора.

Так что снимать "истинную" константность опасно, потому что есть опасность нарваться на глюки, а "предписанную" опасно потому, что можно нарушить семантику константности объекта (то есть нарушить обещание не менять "значение" объекта).
Но первичным, тем не менее, тут является именно обещание не изменять "значение" объекта, а не какие-то там правила. Другое дело, что правила С++ обычно сразу подходят в большинсте случаев и нет нужды изобретать какую-то хитрую схему управления константностью объекта.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.