const Date& default_date
{
static const Date dd(1970,1,1); // инициализируем dd
// только при первом вызове
return dd;
}
Статическая локальная переменная инициализируется (создается) только при первом вызове функции, в которой она объявлена. Обратите внимание на то, что мы вернули ссылку, чтобы исключить ненужное копирование, и, в частности, вернули константную ссылку, чтобы предотвратить несанкционированное изменение значения аргумента при вызове функции. Рассуждения о передаче аргумента (см. раздел 8.5.6) относятся и к возвращаемому значению.
8.7. Пространства имен
Для организации кода в рамках функции используются блоки (см. раздел 8.4).
Для организации функций, данных и типов в рамках типа используется класс (глава 9). Предназначение функций и классов заключается в следующем.
• Они позволяют определить множество сущностей без опасения, что их имена совпадут с другими именами в программе.
• Позволяют именовать то, что мы определили.
Нам нужно иметь средство для организации классов, функций, данных и типов в виде идентифицируемой и именованной части программы, не прибегая к определению типа. Языковый механизм, позволяющий осуществить такую группировку объявлений, называют
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 { /* ... */ };
// ...
}
Если бы мы использовали оба пространства имен одновременно, то столкнулись бы с реальной проблемой. В этом случае действительно возникла бы коллизия между именами классов Text
Line
. И что еще хуже, если бы мы были не создателями, а пользователями библиотеки, то не никак не смогли бы изменить эти имена и решить проблему. Использование пространств имен позволяет избежать проблем; иначе говоря, наш класс Text
— это класс Graph_lib::Text
, а ваш — TextLib::Text
. Имя, составленное из имени пространства имен (или имени класса) и имени члена с помощью двух двоеточий, ::
, называют 8.7.1. Объявления using и директивы using
Писать полностью определенные имена довольно утомительно. Например, средства стандартной библиотеки языка С++ определены в пространстве имен std
#include
#include
int main
{
std::string name;
std::cout << " Пожалуйста, введите имя \n";
std::cin >> name;
std::cout << " Привет, " << name << '\n';
}
Тысячи раз обращаясь к элементам стандартной библиотеки string
cout
, мы на самом деле вовсе не хотим каждый раз указывать их полностью определенные имена — std::string
и std::cout
. Напрашивается решение: один раз и навсегда указать, что под классом string
мы имеем в виду класс std::string
, а под потоком cout
— поток std::cout
и т.д.using std::string; // string означает std::string
using std::cout; // cout означает std::cout
// ...