Г. Шилтд - Самоучитель C++ (PDF) (1114887), страница 57
Текст из файла (страница 57)
Когда вы вводите некоторое пространство имен в текущую областьвидимости, его имена просто добавляются в эту область, независимо от того,находятся ли в ней в это время имена из других пространств имен. Такимобразом, ко времени завершения программы в глобальное пространство именбыли добавлены пространства имен std, firstNS и secondNs.2. Как уже упоминалось, пространство имен можно разделить либо между файлами, либо внутри одного файла, тогда содержимое этого пространства именобъединяется. Рассмотрим пример объединения разделенного пространстваимен.// Объединение пространства имен^include <iostreara>using namespace std;namespace Demo {int a; // объявление переменной а в пространстве имен Demoint x; // объявление переменной х в глобальном пространстве именnamespace Demo {int b; // объявление переменной Ь в пространстве имен Demo'int rnain{)/using namespace Demo;a = b = x = 100;cout « a « " " « b « " " « x;return 0;В данном примере обе переменные, а и b, оказались в одном пространствеимен — пространстве имен Demo, а переменная х осталась в глобальномпространстве имен.3.
Как уже упоминалось, стандарт Standard C++ определяет целую библиотекув собственном пространстве имен std. Именно по этой причине во всехпрограммах этой книги имеется следующая инструкция:using namespace std;Эта инструкция делает пространство имен std текущим, что позволяет получить прямой доступ к именам функции и классов, определенных в библиотеке языка Standard C++, без необходимости каждый раз с помощью оператораСамоучитель С++390расширения области видимости уточнять, что используется пространствоимен std.Тем не менее, если пожелаете, можете перед каждым идентификатором ставитьимя пространства имен std и оператор расширения области видимости ошибки не будет. Например, в следующей программе библиотека языка Standard C++ не введена в глобальную область видимости.// Явное задание используемого пространства имен^include <iostream>int main ()double val;std::cout « "Введите число: ";std; :cin » val;std::cout « "Вот ваше число: ";std::cout « val;return 0;Как показано в данной программе, чтобы воспользоваться стандартнымипотоками ввода и вывода cin и cout, перед именами этих потоков необходимоявно указывать их пространство имен.Если в вашей программе не предусмотрено широкое использование библиотеки языка Standard C++, вы можете не вводить пространство имен std вглобальную область видимости.
Однако, если в вашей программе содержатсятысячи ссылок на стандартные библиотечные имена, включить в программуидентификатор std гораздо проще, чем добавлять его чуть ли не к каждойинструкции.4. Если в своей программе вы используете только несколько имен из стандартной библиотеки, может оказаться удобней с помощью инструкции using отдельно задать эти несколько имен. Преимущество такого подхода в том, чтоуказанные имена можно вносить в программу без необходимости их уточнения, и в то же время не нужно вводить всю стандартную библиотеку в глобальное пространство имен. Рассмотрим пример:// Введение в глобальное пространство только нескольких имен^include <iostream>// обеспечение доступа к потокам cin и coutusing std::cout;using std: :cin;int{main()double val;Глава 13. Пространства имен и другие темы391cout « "Введите число: ";cin » val;cout « "Вот ваше число: ";cout « val;return 0;Здесь стандартными потоками ввода и вывода cin и cout можно пользоватьсянапрямую, но в то же время остальные имена из пространства имен std оставлены вне текущей области видимости.5.
Ранее уже говорилось, что библиотека исходного языка C++ была определена в глобальном пространстве имен. Если вам придется модернизироватьстарую программу на C++, то вам понадобится либо включить в нее инструкцию using namespace std, либо перед каждой ссылкой на члена библиотекидописывать имя пространства имен с оператором расширения области видимости std::.
Это особенно важно, если вы замените прежние заголовочныефайлы заголовками нового стиля (без расширения -h). Помните, прежниезаголовочные файлы размещают свое содержимое в глобальном пространствеимен, а заголовки нового стиля — в пространстве имен std.6. В языке С, если вы хотите ограничить область видимости глобального именитолько тем файлом, в котором это имя объявлено, вы должны объявить егокак статическое, т. е. с идентификатором static. Например, предположим, чтоследующие два файла являются частью одной программы:Первый файлstatic int counter;void fl() {counter = 99; // OKВторой файлextern int counter;void f 2 ( ) {counter =10; // ОшибкаПоскольку переменная counter определена в первом файле, то и использоватьее можно в первом файле.
Во втором файле, несмотря на указание в инструкции с переменной counter идентификатора extern, попытка использованияэтой переменной ведет к ошибке. Объявляя в первом файле переменнуюcounter статической, мы ограничиваем ее область видимости этим файлом.Хотя объявления глобальных переменных с идентификатором static в C++по-прежнему доступны, для достижения той же цели здесь имеется лучшийпуть — использовать, как показано в следующем примере, безымянное пространство имен.Первый файлnamespace {int counter;1void f l ( ) {counter = 99; // OKВторой файлextern int counter;void f 2 ( ){counter = 10; // Ошибка392Самоучитель C++Здесь область видимости переменной counter также ограничена первым файлом. Использовать безымянное пространство имен вместо ключевого словаstatic рекомендует новый стандарт Standard C++.I.
Переделайте представленную ниже программу из главы 9 так, чтобы в нейотсутствовала инструкция using namespace std.// Превращение пробелов в вертикальные линии |ftinclude <iostream>^include <fstream>using namespace std;int main{int argc, char *argv[])(if(argc!=3) {cout « "Преобразование <файл ввода> <файл вывода>\п";return 1;ifstrearn fin (argvfl]); // открытие файла для вводаofstreara fout(argv[2]); // создание файла для выводаif{!fout} {cout « "Файл открыть невозможно\п";return 1;}if(!fin) {cout « "Файл открыть невоэможно\п";return 1;}char ch;fin.unsetf(ios::skipws); // не пропускать пробелыwhile{!fin.eof{)) {fin » ch;if(ch==' ') ch = '|';if (!fin.eof()) fout « ch;fin.close();fout.close();return 0;}•Глава 13.
Пространства имен и другие темы3932. Объясните назначение безымянного пространства имен.3. Опишите различия между двумя формами инструкции using.4. Объясните, почему в подавляющее большинство программ данной книгивведена инструкция using. Приведите альтернативу ее использованию.5. Объясните почему, если вы создаете многократно используемый код, его желательно размещать в собственном пространстве имен.13.2. функции преобразованияИногда бывает полезно преобразовать объект одного типа в объект другоготипа.
Хотя для этого можно воспользоваться перегруженной операторфункцией, часто более легким (и лучшим) способом такого преобразованияявляется функция преобразования. Функция преобразования (conversionfunction) преобразует объект в значение, совместимое с другим типом данных, который часто является одним из встроенных типов данных C++.Уточним, функция преобразования автоматически преобразует объект в значение, совместимое с типом выражения, в котором этот объект используется.Здесь показана основная форма функции преобразования:operator тип () { return значение; }••Здесь тип — это целевой тип преобразования, а значение — это значениеобъекта после выполнения преобразования.
Функции преобразования возвращают значение типа тип. У функции преобразования не должно бытьпараметров, и она должна быть членом класса, для которого выполняетсяпреобразование.Как будет показано в примерах, обычно функция преобразования обеспечивает более ясный подход к преобразованию значения объекта в другой тип,чем любой другой метод C++, поскольку она позволяет явно включить объект в выражение, содержащее переменные целевого типа.В следующей программе класс coord содержит функцию преобразования,которая преобразует объект в целое. В данном случае функция возвращаетпроизведение двух координат; однако в каждом конкретном случае допускается любое необходимое действие.// Простой пример функции преобразованияttinclude <iostream>using namespace std;394__Самоучитель C++class coord {int x, у;public:coord{int i, int j) { x = i; у = j; }operator int{) { return x*y; } // функция преобразованияint main()coord ol(2, 3), o2(4, 3) ;int i;i = ol; // объект ol автоматически преобразуется в целоеcout « i « '\n';i = 100 4 o2; // объект о2 преобразуется в целоеcout « i « '\n';return 0;В результате выполнения этой программы на экран будут выведены значения6 и 112.Обратите внимание, что функция преобразования вызывается тогда, когдаобъект ol присваивается целому, а также когда объект о2 используется, какчасть большого выражения, оперирующего с целыми.
Как уже установлено, спомощью функции преобразования вы разрешаете вставлять объекты созданных вами классов в "обычные" выражения, без образования сложных цепочек перегруженных оператор- функций.2. Следующим представлен другой пример функции преобразования. Здесьпреобразуется строка типа strtype в символьный указатель на str.ttinclude <iostream>^include <cstring>using namespace std;class strtype {char str[80] ;int len;public:strtype [char *s) { strcpy(str, s); len = strlen(s); }operator char *() { return str; } // преобразование в тип char *int main(){strtype з{"Это проверка \n" };char *p, s 2 [ 8 0 J ;Глава13.Пространстваименидругиетемы _ 395_р = s; // преобразование в тип char *cout « "Это строка: " « р « ' \ п ' ;// при вызове функции преобразуется в тип char *strcpy{s2, s) ;cout « "Это копия строки: " « s2 « ' \ n ' ;-return 0;Эта программа выводит на экран следующее:Это строка: Это проверкаЭто копия строки: Это проверкаКак можно заметить, функция преобразования вызывается не только приприсваивании объекта s объекту р (который имеет тип char *), но она такжеиспользуется как параметр для функции strcpy().