С.Б. Липпман, Ж. Лажойе - Язык программирования С++ Вводный курс (1114944), страница 70
Текст из файла (страница 70)
Например, приведенная using-директива создаетиллюзию того, что все члены cplusplus_primer объявлены в глобальной областивидимости перед определением func(). При этом члены пространства имен не получаютnamespace A {int i, j;локальных псевдонимов, а как бы перемещаются в новую область видимости. Код}выглядит как417С++ для начинающих418int i, J;для фрагмента программы, содержащего в области видимости следующую usingдирективу:using namespace A;Рассмотрим пример, позволяющий подчеркнуть разницу между using-объявлением(которое сохраняет пространство имен, но создает ассоциированные с его членамилокальные синонимы) и using-директивой (которая полностью удаляет границыnamespace blip {int bi = 16, bj = 15, bk = 23;// прочие объявления}int bj = 0;void manip() {using namespace blip; ////////++bi;//++bj;////++::bj;//++blip::bj;//int bk = 97;++bk;using-директива коллизия имен ::bj and blip::bjобнаруживается только прииспользовании bjblip::bi == 17ошибка: неоднозначностьглобальная bj или blip::bj?правильно: глобальная bj == 1правильно: blip::bj == 16// локальная bk скрывает blip::bk// локальная bk == 98пространства имен).}Во-первых, using-директивы имеют область видимости.
Такая директива в функцииmanip() относится только к блоку этой функции. Для manip() члены пространства именblip выглядят так, как будто они объявлены в глобальной области видимости, аследовательно, можно использовать их неквалифицированные имена.
Вне этой функциинеобходимо употреблять квалифицированные.Во-вторых, ошибки неоднозначности, вызванные применением using-директивы,обнаруживают себя при реальном обращении к такому имени, а не при встрече в текстесамой этой директивы. Например, переменная bj, член пространства blib, выглядит дляmanip() как объявленная в глобальной области видимости, вне blip. Однако вглобальной области уже есть такая переменная. Возникает неоднозначность имени bj вфункции manip(): оно относится и к глобальной переменной, и к члену пространстваblip.
Ошибка проявляется только при упоминании bj в функции manip(). Если бы этоимя вообще не использовалось в manip(), коллизия не проявилась бы.В-третьих, using-директива не затрагивает употребление квалифицированных имен.Когда в manip() упоминается ::bj, имеется в виду переменная из глобальной областивидимости, а blip::bj обозначает переменную из пространства имен blip.И наконец члены пространства blip выглядят для функции manip() так, как будто ониобъявлены в глобальной области видимости. Это означает, что локальные объявлениявнутри manip() могут скрывать имена членов пространства blip. ЛокальнаяС++ для начинающихпеременная bk скрывает blip::bk.
Ссылка на bk внутри manip() не являетсянеоднозначной – речь идет о локальной переменной.Using-директивы использовать очень просто: стоит написать одну такую директиву, и всечлены пространства имен сразу становятся видимыми. Однако чрезмерное увлечение имиnamespace cplusplus_primer {class matrix { };// прочие вещи ...}namespace DisneyFeatureAnimation {class matrix { };// здесь тоже ...using namespace cplusplus_primer;using namespace DisneyFeatureAnimation;matrix m; //ошибка, неоднозначность:возвращает нас к старой проблеме засорения глобального пространства имен:// cplusplus_primer::matrix или DisneyFeatureAnimation::matrix?Ошибки неоднозначности, вызываемые using-директивой, обнаруживаются только вмомент использования.
В данном случае – при употреблении имени matrix. Такаяошибка, найденная не сразу, может стать сюрпризом: заголовочные файлы не менялись иникаких новых объявлений в программу добавлено не было. Ошибка появилась послетого, как мы решили воспользоваться новыми средствами из библиотеки.Using-директивы очень полезны при переводе приложений на новые версии библиотек,использующие пространства имен. Однако употребление большого числа using-директиввозвращает нас к проблеме засорения глобального пространства имен.
Эту проблемуможно свести к минимуму, если заменить using-директивы более селективными usingобъявлениями. Ошибки неоднозначности, вызываемые ими, обнаруживаются в моментобъявления. Мы рекомендуем пользоваться using-объявлениями, а не using-директивами,чтобы избежать засорения глобального пространства имен в своей программе.8.6.4.
Стандартное пространство имен stdВсе компоненты стандартной библиотеки С++ находятся в пространстве имен std.Каждая функция, объект и шаблон класса, объявленные в стандартном заголовочномфайле, таком, как <vector> или <iostream>, принадлежат к этому пространству.Если все компоненты библиотеки объявлены в std, то какая ошибка допущена в данномпримере:419С++ для начинающих420#include <vector>#include <string>#include <iterator>int main(){// привязка istream_iterator к стандартному вводуistream_iterator<string> infile( cin );// istream_iterator, отмечающий end-of-streamistream_iterator<string> eos;// инициализация svec элементами, считываемыми из cinvector<string> svec( infile, eos );// ...}Правильно, этот фрагмент кода не компилируется, потому что члены пространства именstd должны использоваться с указанием их специфицированных имен. Для того чтобыисправить положение, мы можем выбрать один из следующих способов:•заменить имена членов пространства std в этом примере соответствующимиспецифицированными именами;•применить using-объявления, чтобы сделать видимыми используемые членыпространства std;•употребить using-директиву, сделав видимыми все члены пространства std.Членами пространства имен std в этом примере являются: шаблон классаistream_iterator, стандартный входной поток cin, класс string и шаблон классаvector.Простейшеерешение –препроцессора #include:добавитьusing-директивупоследирективыusing namespace std;В данном примере using-директива делает все члены пространства std видимыми.Однако не все они нам нужны.
Предпочтительнее пользоваться using-объявлениями,чтобы уменьшить вероятность коллизии имен при последующем добавлении в программуглобальных объявлений.using std::istream_iterator;using std::string;using std::cin;Using-объявления, необходимые для компиляции этого примера, таковы:using std::vector;Но куда их поместить? Если программа состоит из большого количества файлов, можнодля удобства создать заголовочный файл, содержащий все эти using-объявления, ивключать его в исходные файлы вслед за заголовочными файлами стандартнойбиблиотеки.С++ для начинающихВ нашей книге мы не употребляли using-объявлений. Это сделано, во-первых, для того,чтобы сократить размер кода, а во-вторых, потому, что большинство примеровкомпилировались в реализации С++, не поддерживающей пространства имен.Подразумевается, что using-объявления указаны для всех членов пространства имен std,используемых в примерах.Упражнение 8.14Поясните разницу между using-объявлениями и using-директивами.Упражнение 8.15Напишите все необходимые using-объявления для примера из раздела 6.14.Упражнение 8.16namespace Exercise {int ivar = 0;double dvar = 0;const int limit = 1000;}int ivar = 0;//1void manip() {//2double dvar = 3.1416;int iobj = limit + 1;++ivar;++::ivar;Возьмем следующий фрагмент кода:}Каковы будут значения объявлений и выражений, если поместить using-объявления длявсех членов пространства имен Exercise в точку //1? В точку //2? А если вместо usingобъявлений использовать using-директиву?421С++ для начинающих42399.
Перегруженные функцииИтак, мы уже знаем, как объявлять, определять и использовать функции впрограммах. В этой главе речь пойдет об их специальном виде – перегруженныхфункциях. Две функции называются перегруженными, если они имеют одинаковоеимя, объявлены в одной и той же области видимости, но имеют разные спискиформальных параметров. Мы расскажем, как объявляются такие функции и почемуони полезны. Затем мы рассмотрим вопрос об их разрешении, т.е. о том, какаяименно из нескольких перегруженных функций вызывается во время выполненияпрограммы. Эта проблема является одной из наиболее сложных в C++. Тем, ктохочет разобраться в деталях, будет интересно прочитать два раздела в конце главы,где тема преобразования типов аргументов и разрешения перегруженных функцийраскрывается более подробно.9.1.
Объявления перегруженных функцийТеперь, научившись объявлять, определять и использовать функции в программах,познакомимся с перегрузкой – еще одним аспектом в C++. Перегрузка позволяет иметьнесколько одноименных функций, выполняющих схожие операции над аргументамиразных типов.Вы уже воспользовались предопределенной перегруженной функцией. Например, длявычисления выражения1 + 3вызывается операция целочисленного сложения, тогда как вычисление выражения1.0 + 3.0осуществляет сложение с плавающей точкой.