Б. Страуструп - Дизайн и Эволюция C++. 2006 (1160775), страница 73
Текст из файла (страница 73)
раздел 3.11А). Данное правило позволяет инициализировать кои. стантиые объекты во время выполнения, но допускает также и размешеиие в ПЗУ тех объектов, которые в такой инициализации ие нуждаются. Типичным примером служит большой массив простых обьектов, скажем, таблица, сгенерированиая синтаксическим анализатором УАСС. Привязка концепции с опас к конструкторам была компромиссом между самой идеей сопзс, соображением о том, что программисту нужно доверять, и существуюшей ситуацией в области аппаратного обеспечения.
По предложению Джерри Константные функции-члены ..'1ИИИИИИП Шварца это правило было заменено другим, более точно отражающим мое первоначальное намерение относительно сонэ с. Объект, объявленный как сопя с, считается неизменным с момента завершения конструирования ло начала работы деструктора. Результат опсрапии записи в объект между этими двумя моментами не определен. Когда я первоначально проектировал концепцию сопзг, то, помнится, говорил, что в идеале константный объект был бы записываемым, пока нс оз работал до конца конструктор, затем становился доступным только для чтения, а после входа в деструктор он снова мог изменяться.
Можно вообразить себе тэгироваппую архитектуру, благодаря которой обеспечивается подобнос поведение. При такой реализации возникала бы ошибка во время выполнения при попытке изменить объект, объявленный как сопзс. С другой стороны, можно бгало бы попробовать изменить объект, пс объявленный с модификатором сопзг, по переданный по константной ссылке или указателю. В обоих случаях пользователь сначала должен «снять констаптность«В результате отмена сопя е для объекта, ко~орый первоначально был объявлен константным, и последующее его изменение приводят к непредсказуемому результату.
Но тс жс действия, примененные к объекту, который не был изначально объявлен константным, вполне законны и четко определены. Отметим, что после такого уточнения правил семантика сопя г не зависит от того, имеет ли тип конструктор или нет; в принципе конструктор сеть у всех типов. Любой объект, обьявлснный как сопзс, теперь можно размещать в ПЗУ, в сегменте кода, защищать с помощью контроля доступа и т.д, — все это с целью гарантировать неизменность после первоначальной инициализации. Такая зашита, однако, пс является обязательной, так как современные системы в основном нс в состоянии предохранить каждый константный объект от всех видов искажения. Реализация все еще оставляет болыпую свободу выбора в том, как следует управлять константными объектами.
Не возникает логической проблемы в случае, если сборщик мусора или система баз данных изменит значение константного объекта (например, перенесет его на диск или обратно), цри условии, что для пользователя объект булет выглядеть неизменившимся. О.З.З.
Ключевое слово ти1вЫе и приведение типов Снятие модификатора сонэк все-таки вызывает некоторые возражения: во-первых, это разновидность приведения типов, во-вторых, не гарантируется правильная работа во всех случаях. Как можно написать класс типа хх (см. раздел 13.3.1), который не нуждался бы ни в приведении типов, ни в косвенном обращении, как в классе ххх? Томас Нго (Тпощаз Хйо) прелложил, что должна быть возможность объянить член таким образом, чтобы оц никогда не считался константным, даже если является членом константного объекта. Данное црслложение рассматривалось в комитете в течение нескольких лет, пока Джерри Шварц не нашел вариант, который всех устроил.
Первоначально предлагалась нотация -сопзс для выражения семантики «никогда не может быть сопзг». Даже некоторые сторонники самой концепции считали такую нотацию слишком неудачной, поэтому в одобренном комитетом АЫБ1/150 варианте фигурировало ключевос слово гацсаЬ1е: Уточнения понятия класса ИИИИИИИ1.' с1авв хХХ 1пг а; ипгаЫе 1пг спг; // спг никогда не может быть сопев рпЬ11с: ьгс г() сопев ( спг++; гегигп а; ) // чаг.спг изменяема (разумеется) ххх чаг; сопев ХХХ спвг; // спас.спг изменяема, так как // Ххх::спг объявлен со словом ипгаЫе Концепция действительно снижает потребность в приведениях типов в реальных системах, но не до такой степени, как ожидалось.
Даг Брюк и другие изучили много реальных программ для уточнения того, какие приведения использовались для снятия константности и от каких можно было бы отказаться за счет пцсаЬ1е. Исследование подтвердило вывод о том, что в общей ситуации от «снятия с оп э с» нельзя отказаться (см, раздел 143 А) и что слово и цг аЬ1е позволяет избежать этого менее чем в половине случаев. Преимушества, которые дает пцс аЬ1е, похоже, сильно зависят от стиля программирования. В каких-то программах все приведения можно было бы заменить использованием /писаЬ1е, а в других — ни одного.
Некоторые пользователи надеялись, что пересмотр концепции сопзс и введение жис аЬ1е открывают дорогу серьезным оптимизациям кода. Вряд ли это так. Основное достоинство — повышение ясности кода и увеличение числа объектов с предвычисленными значениями, которые можно поместить в ПЗУ, сегменты кода и т.д.
13.4. Статические функции-члены Статический (эсасйс) член-данные класса — это такой член, копия которого существует в единственном экземпляре, а не в каждом объекте. Значит, к статическому члену можно получить доступ, не ссылаясь ни на какой объект. Статические члены уменьшают число глобальных имен, делают очевидным, к какому классу логически принадлежат статические объекты; также обращение к ним осуществляется в соответствии с правилами контроля доступа. Это, безусловно, удобно для поставщиков библиотек, поскольку позволяет избежать загрязнения глобального пространства имен и, следовательно„упрощает написание кода библиотеки и делает более безопасной работу с несколькими библиотеками.
Данные соображения применимы к функциям в той же мере, что и к объектам. Поставщик библиотеки обычно хочет сделать неглобальными имена функций. Я заметил, что для имитации статических функций-членов применялись непереносимые конструкции вроде ( (х*) О ) ->й ( ) . Этот прием — бомба замедленного действия, поскольку рано или поздно кто-то объявит функцию, вызываемую таким образом, виртуальной.
Тогда последствия вызова будут непредсказуемы, ибо по нулевому адресу нет объекта класса х. Но даже если й () невиртуальная функция, НИИИ ИИБИ Статические функции-члены такие вызовы завершатся неудачно при работе с некоторыми компиляторами, поддерживающими динамическое связывание. Во время курса, который я читал в 1987 г. для Е(ЛЗС (Европейская группа пользователей ()Н1Х) в Хельсинки, Мартин О'Риордан указал мне, что статические функции-члены — очевидное и полезное обобщение.
Возможно, именно тогда эта идея и прозвучала впервые. Мартин в то время работал в ирландской компании б!ос!сепзр(е1, а позже стал главным архитектором компилятора М!сгозой С++. Позже Джонатан Шопиро поддержал зту идею и не дал ей затеряться во время работы над версией 2.0. Статическая функция-член остается членом класса, значит, ее имя находится в области действия класса и к нему применимы обычные правила контроля доступа. Например: с1авв гав)с ( // вгасьс гав)с* с)1а1п; рпп11с: вга 1с уовд аспас)п1е(1пс); // ): Объявление статического члена — зто всего лишь объявление, так что соответствующий объект или функция должны иметь где-то в программе единственное определение.
Например: гавх* гавх::сааза = О; уорд Савк::вс)1еоп1е(1пс р) ( /* ... */ Статическая функция-член не ассоциирована ни с каким конкретным объектом, и для ее вызова не нужен специальный синтаксис для функций-членов. Например: уорд Г(1пс рггог1 у) ( // Савх::всйес)п1е(рг1ог1гу),' // ) 13.5.
Вложенные классы Как уже отмечалось в разделе 3.12, вложенные классы повторно введены в С++ в АКМ. Это сделало более регулярными правила областей действия и улучшило средства локализации информации. Теперь стало возможно написать: В некоторых случаях класс используется просто как область действия, в которую глобальные имена помещаются пол видом статических членов, чтобы не засорять глобальное пространство имен. Это является одним из источников концепции пространств имен (см.