Вход/Регистрация
Программирование. Принципы и практика использования C++ Исправленное издание
вернуться

Страуструп Бьерн

Шрифт:

// файл f2.cpp

extern int y1;

int y2 = y1+2; // переменная y2 становится равной 2 или 5

Такой код нежелателен по нескольким причинам: в нем используются глобальные переменные, которые имеют слишком короткие имена, и сложная инициализация глобальных переменных. Если глобальные переменные в файле

f1.cpp
инициализируются до глобальных переменных в файле
f2.cpp
, то переменная
y2
будет инициализирована числом
5
(как наивно ожидает программист).

Однако, если глобальные переменные в файле

f2.cpp
инициализируются до глобальных переменных в файле
f1.cpp
, переменная
y2
будет инициализирована числом
2
(поскольку память, используемая для глобальных переменных, инициализируется нулем до попытки сложной инициализации). Избегайте этого и старайтесь не использовать нетривиальную инициализацию глобальных переменных; любой инициализатор, отличающийся от константного выражения, следует считать сложным.

Но что же делать, если нам действительно нужна глобальная переменная (или константа) со сложной инициализацией? Например, мы можем предусмотреть значение по умолчанию для переменных типа

Date
.

const Date default_date(1970,1,1); // дата по умолчанию: 1 января 1970

Как узнать, что переменная

default_date
никогда не использовалась до своей инициализации? В принципе мы не можем этого знать, поэтому не должны писать это определение. Чаще всего для проверки используется вызов функции, возвращающей некое значение. Рассмотрим пример.

const Date default_date // возвращает дату по умолчанию

{

return Date(1970,1,1);

}

Эта функция создает объект типа

Date
каждый раз, когда вызывается функция
default_date
. Часто этого вполне достаточно, но если функция
default_date
вызывается часто, а создание объекта класса Date связано с большими затратами, предпочтительнее было бы конструировать его только один раз. В таком случае код мог бы выглядеть так:

const Date& default_date

{

static const Date dd(1970,1,1); // инициализируем dd

// только при первом вызове

return dd;

}

Статическая локальная переменная инициализируется (создается) только при первом вызове функции, в которой она объявлена. Обратите внимание на то, что мы вернули ссылку, чтобы исключить ненужное копирование, и, в частности, вернули константную ссылку, чтобы предотвратить несанкционированное изменение значения аргумента при вызове функции. Рассуждения о передаче аргумента (см. раздел 8.5.6) относятся и к возвращаемому значению.

8.7. Пространства имен

Для организации кода в рамках функции используются блоки (см. раздел 8.4).

Для организации функций, данных и типов в рамках типа используется класс (глава 9). Предназначение функций и классов заключается в следующем.

• Они позволяют определить множество сущностей без опасения, что их имена совпадут с другими именами в программе.

• Позволяют именовать то, что мы определили.

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

Color
,
Shape
,
Line
,
Function
и
Text
(глава 13).

namespace Graph_lib {

struct Color { /* ... */ };

struct Shape { /* ... */ };

struct Line: Shape { /* ... */ };

struct Function: Shape { /* ... */ };

struct Text: Shape { /* ... */ };

// ...

int gui_main { /* ... */ }

}

Очень вероятно, что вы также захотите использовать эти имена, но теперь это уже не имеет значения. Вы можете определить сущность с именем

Text
, но ее уже невозможно перепутать с нашим классом, имеющим то же имя. Наш класс называется
Graph_lib::Text
, а ваш класс — просто
Text
. Проблема возникнет только в том случае, если в вашей программе есть класс или пространство имен
Graph_lib
, в которое входит класс
Text
. Имя
Graph_lib
довольно неудачное; мы выбрали его потому, что “прекрасное и очевидное” имя
Graphics
имеет больше шансов встретиться где-нибудь еще.

Допустим, ваш класс

Text
является частью библиотеки для обработки текстов. Та же логика, которая заставила нас разместить графические средства в пространстве имен
Graph_lib
, подсказывает, что средства для обработки текстов следует поместить в пространстве имен, скажем, с именем
TextLib
.

namespace TextLib {

class Text { /* ... */ };

class Glyph { /* ... */ };

class Line { /* ... */ };

  • Читать дальше
  • 1
  • ...
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: