{
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 { /* ... */ };
// ...
}
Если бы мы использовали оба пространства имен одновременно, то столкнулись бы с реальной проблемой. В этом случае действительно возникла бы коллизия между именами классов
Text
и
Line
. И что еще хуже, если бы мы были не создателями, а пользователями библиотеки, то не никак не смогли бы изменить эти имена и решить проблему. Использование пространств имен позволяет избежать проблем; иначе говоря, наш класс
Text
— это класс
Graph_lib::Text
, а ваш —
TextLib::Text
. Имя, составленное из имени пространства имен (или имени класса) и имени члена с помощью двух двоеточий,
::
, называют
полностью определенным именем (fully qualified name).
8.7.1. Объявления using и директивы using
Писать полностью определенные имена довольно утомительно. Например, средства стандартной библиотеки языка С++ определены в пространстве имен
std
и могут использоваться примерно так:
#include<string> // доступ к библиотеке string
#include<iostream> // доступ к библиотеке iostream
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
и т.д.