Неименованные пространства имен



 

Неименованное пространство имен ограничивает идентификаторы рамками файла, в котором они объявлены.

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

 

 

Неименованные пространства имен позволяют устанавливать уникальные идентификаторы, которые известны только в области видимости одного файла. Другими словами, члены файла, который содержит неименованное пространство имен, можно использовать напрямую, без уточняющего префикса. Но вне файла эти идентификаторы неизвестны.

Как упоминалось выше в этой книге, использование модификатора типа static также позволяет ограничить область видимости глобального пространства имен файлом, в котором он объявлен. Например, рассмотрим следующие два файла, которые являются частью одной и той же программы.

 

 

Поскольку переменная k определена в файле One , ее и можно использовать в файле One . В файле Two переменная k определена как внешняя (extern‑переменная), а это значит, что ее имя и тип известны, но сама переменная k в действительности не определена. Когда эти два файла будут скомпонованы, попытка использовать переменную k в файле Two приведет к возникновению ошибки, поскольку в нем нет определения для переменной k . Тот факт, что k объявлена static ‑переменной в файле One , означает, что ее область видимости ограничивается этим файлом, и поэтому она недоступна для файла Two .

Несмотря на то что использование глобальных static ‑объявлений все еще разрешено в C++, для локализации идентификатора в рамках одного файла лучше использовать неименованное пространство имен. Рассмотрим пример.

 

 

Здесь переменная k также ограничена рамками файла One . Для новых программ рекомендуется использовать вместо модификатора static неименованное пространство имен.

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

 

Пространство имен std

 

Пространство имен std используется библиотекой C++.

Стандарт C++ определяет всю свою библиотеку в собственном пространстве имен, именуемом std . Именно по этой причине большинство программ в этой книге включает следующую инструкцию:

 

 

При выполнении этой инструкции пространство имен std становится текущим, что открывает прямой доступ к именам функций и классов, определенных в этой библиотеке, т.е. при обращении к ним отпадает необходимость в использовании префикса std:: .

Конечно, при желании можно явным образом квалифицировать каждое библиотечное имя префиксом std:: . Например, следующая программа не привносит библиотеку в глобальное пространство имен.

 

 

Здесь имена cout и cin явно дополнены именами своих пространств имен. Итак, чтобы записать данные в стандартный выходной поток, следует использовать не просто имя потока cout , а имя с префиксом std::cout , а чтобы считать данные из стандартного входного потока, нужно применить "префиксное" имя std::cin .

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

Если вы используете только несколько имен из стандартной библиотеки, то, вероятно, имеет смысл использовать инструкцию using для каждого из них в отдельности. Преимущество этого подхода состоит в том, что эти имена можно по‑прежнему использовать без префикса std:: , не внося при этом всю библиотеку стандартных функций в глобальное пространство имен. Рассмотрим пример.

 

 

Здесь имена потоков cin и cout можно использовать напрямую, но остальная часть пространства имен std не внесена в область видимости.

Как упоминалось выше, исходная библиотека C++ была определена в глобальном пространстве имен. Если вам придется модернизировать старые С++‑программы, то вы должны либо включить в них инструкцию using namespace std , либо дополнить каждое обращение к члену библиотеки префиксом std:: . Это особенно важно, если вам придется заменять старые заголовочные *.h ‑файлы современными заголовками. Помните, что старые заголовочные *.h ‑файлы помещают свое содержимое в глобальное пространство имен, а современные заголовки – в пространство имен std .

 

Указатели на функции

 

Указатель на функцию ссылается на входную точку этой функции.

Указатель на функцию– это довольное сложное, но очень мощное средство C++. Несмотря на то что функция не является переменной, она, тем не менее, занимает физическую область памяти, некоторый адрес которой можно присвоить указателю. Адрес, присваиваемый указателю, является входной точкой функции. (Именно этот адрес используется при вызове функции.) Если некоторый указатель ссылается на функцию, то ее (функцию) можно вызвать с помощью этого указателя.

Указатели на функции также позволяют передавать функции в качестве аргументов другим функциям. Адрес функции можно получить, используя имя функции без круглых скобок и аргументов. (Этот процесс подобен получению адреса массива, когда также используется только его имя без индекса.) Если присвоить адрес функции указателю, то эту функцию можно вызвать через указатель. Например, рассмотрим следующую программу. Она содержит две функции, vline() и hline() , которые рисуют на экране вертикальные и горизонтальные линии заданной длины.

 

 

Вот как выглядят результаты выполнения этой программы.

 

 

Рассмотрим эту программу в деталях. В первой строке тела функции main() объявляется переменная р как указатель на функцию, которая принимает один целочисленный аргумент и не возвращает никакого значения. Это объявление не определяет, какая функция имеется в виду. Оно лишь создает указатель, который можно использовать для адресации любой функции этого типа. Необходимость круглых скобок, в которые заключен указатель , следует из С++‑правил предшествования.

В следующей строке указателю р присваивается адрес функции vline() . Затем выполняется вызов функции vline() с аргументом 4 . После этого указателю р присваивается адрес функции hline() , и с помощью этого указателя реализуется ее вызов.

В этой программе при вызове функций посредством указателя используется следующий формат:

 

 

Однако функцию, адресуемую указателем р , можно вызвать с использованием более простого синтаксиса:

 

 

Единственная причина, по которой чаще используется первый вариант вызова функции, состоит в том, что всем, кто станет разбирать вашу программу, станет ясно, что здесь реализован вызов функции через указатель р , а не вызов функции с именем р . Во всем остальном эти варианты эквивалентны.

Несмотря на то что в предыдущем примере указатель на функцию используется только ради иллюстрации, зачастую такое его применение играет очень важную роль. Указатель на функцию позволяет передавать ее адрес другой функции. В качестве показательного примера можно привести функцию qsort() из стандартной С++‑библиотеки. Функция qsort() – это функция быстрой сортировки, основанная на алгоритме Quicksort , который упорядочивает содержимое массива. Вот как выглядит ее прототип.

 

 

Функция qsort()это функция сортировки из стандартной С++‑библиотеки.

Прототип функции qsort() "прописан" в заголовке <cstdlib> , в котором также определен тип size_t (как тип unsigned int). Чтобы использовать функцию qsort() , необходимо передать ей указатель на начало массива объектов, который вы хотите отсортировать (параметр start ), длину этого массива (параметр length ), размер в байтах каждого элемента (параметр size ) и указатель на функцию сравнения элементов массива (параметр *compare ).

Функция сравнения, используемая функцией qsort() , сопоставляя два элемента массива, должна возвратить отрицательное значение, если ее первый аргумент указывает на значение, которое меньше второго, нуль, если эти аргументы равны, и положительное значение, если первый аргумент указывает на значение, которое больше второго.

Чтобы понять, как можно использовать функцию qsort() , рассмотрим следующую программу.

 

 

Вот как выглядят результаты выполнения этой программы.

 

 

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

 

 

He стану утверждать, что указатели на функции не так просты для понимания, но практика поможет и "с ними найти общий язык" . В отношении указателей на функции необходимо рассмотреть еще один аспект, связанный с перегруженными функциями.

 


Дата добавления: 2018-09-22; просмотров: 307; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!