Тема 10. Области действия и пространства имен 


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



ЗНАЕТЕ ЛИ ВЫ?

Тема 10. Области действия и пространства имен



Каждый программный объект имеет область действия и время жизни, которые определяются видом и местом его определения. Существуют следующие разновидности области действия:

- блок;

- прототип функции;

- функция;

- файл;

- группа файлов, в пределе включающая все файлы программного проекта (глобальная область действия).

- класс;

- пространство имен (часть глобальной области действия).

 

Кратко обсудим все категории областей действия программных объектов.

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

Прототип функции. Идентификаторы, указанные в списке параметров прототипа (объявления) функции имеют областью действия только прототип функции. Поэтому можно использовать произвольные идентификаторы параметров функции и даже вообще их опускать.

Функции. Программные объекты, определенные в блоке функции, имеют область действия и время жизни точно такие же, как и в обычном блоке.

Параметры функции, передаваемые по значению, имеют областью действия всю функцию и временем жизни – время выполнения функции.

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

Файл. Программный объект, определенный с использованием описателя класса хранения static вне любого блока, функции, класса или пространства имен, имеет область действия, начинающуюся в точке определения и заканчивается в конце файла. В область действия включаются вложенные (внутренние) блоки, если в них не содержится переопределение программного объекта с тем же идентификатором. Если же во вложенном блоке переопределен объект с тем же идентификатором, то в этом случае внешний объект во вложенном блоке видим, но к нему, если он глобален (определен вне блока, функции, класса или пространства имен), можно обратиться с помощью операции доступа к области видимости “::”. Время жизни такого объекта максимально и совпадает со временем выполнения программы.

Группа файлов, в пределе включающая все файлы программного проекта (глобальная область действия). Программный объект, определенный только в одном из файлов проекта вне любого блока, функции, класса или пространства имен и объявленный в других файлах с использованием описателя класса хранения extern (внешний) также вне любого блока, функции, класса или пространства имен, имеет область действия, начинающуюся в каждом из таких файлов в точке определения или объявления, и заканчивается в конце файла. В область действия включаются вложенные (внутренние) блоки файлов, если в них не содержится переопределение программного объекта с тем же идентификатором. Время жизни такого объекта максимально и совпадает со временем выполнения программы.

Класс. Члены объектов–классов, за исключением статических членов классов, имеют областью действия класс. Это означает, что они являются видимыми лишь в пределах класса. Время жизни членов объекта–класс определяются промежутком времени от момента создания объекта–класса до момента его разрушения. Статические члены–данные и методы являются глобальными и, в отличие от обычных статических переменных и функций, доступны во всех файлах многофайлового проекта, содержащих описание данного класса.

Статические члены–данные, как и обыкновенные глобальные переменные, обязательно необходимо определить в одном из файлов проекта.

Статические члены–данные и функции–члены доступны и до создания хотя бы одного объекта. Обратиться к ним можно с помощью оператора “::”.

Пространство имен. Язык С++ позволяет явным образом задать область действия имен как часть глобальной области с помощью оператора namespace. В каждой области действия различают так называемые пространства имен. Пространство имен – область, в пределах которой идентификатор должен быть уникальным. В разных пространствах имен идентификаторы могут совпадать, поскольку разрешение ссылок осуществляется по контексту идентификатора в программе, например:

struct Node

{

int Node;

int i;

} Node;

 

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

В языке С++ определено четыре разных пространства имен, в пределах каждого из которых идентификаторы должны быть уникальными:

· Пространство имен, к которому относятся идентификаторы переменных (объектов); функций; типов, определенных пользователем (typedef) и констант перечислений в пределах одной области действия. Все они, кроме идентификаторов функций, могут быть переопределены во вложенных блоках.

· Пространство, которое образуют имена типов перечислений, структур, классов и объединений. В этом пространстве имен каждый такой идентификатор должен быть уникальным в пределах одной области действия.

· Отдельное пространство имен составляют члены каждого класса. Имя члена класса должно быть уникально внутри класса, но может совпадать с именами членов других классов.

· Метки образуют отдельное пространство имен.

 

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

 

Пространство имен (именованная область) служит для логического группирования определений, объявлений и ограничения доступа к ним. Чем больше размер программы, тем более актуально использование именованных областей. С помощью различных пространств имен можно отделить код, написанный одним программистом, от кода, написанного другим, без возможности совпадения и конфликта имен.

Объявление пространства имен (именованной области) имеет следующий формат:

namespace [имя_области] {/* определения и объявления */…}

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

namespace demo

{ int i=0; // определение объекта

int k=0; // определение объекта

void func1(int); // прототип функции

void func2(int r) {…} // определение функции

}

// расширение пространства имен demo

namespace demo

{ // int i=2; // неверно – двойное определение

void func1(double); // верно – прототип функции (перегрузка)

void func2 (int); // верно – прототип функции

}

 

Логично помещать в объявление пространства имен только объявления, а определять их позжее с помощью имени области и оператора доступа к области видимости “::”, например:

void demo :: func1(int n) {…}

Такой прием обеспечивает разделение интерфейса и реализации (таким образом нельзя объявить новый элемент пространства имен).

Если имя часто используется вне своего пространства, то его можно сделать доступным с помощью оператора using:

using demo :: i;

После этого можно использовать имя i без явного указания области. Если требуется сделать доступным все имена из какой-либо области, используется оператор using namespace:

using namespace demo;

Операторы using и using namespace можно использовать и внутри объявления именованной области, чтобы сделать в ней доступными объявления и определения из другой области.

 

Основная литература: 5 [гл.3, 59-80], 6 [гл.4, 103-113], 7 [гл.2, 54-62], 8 [гл.13, 383-393].

 

Контрольные вопросы:

1. Обязательно ли использовать пространство имен?

2. Каковы отличия между использованием using и using namespace?

3. Что такое именованные пространства имен и зачем они нужны?

4. Можно ли использовать идентификаторы, объявленные в пространстве имен без применения служебного слова using?

5. Что такое стандартное пространство имен std?

Тема 11. Ввод-вывод в языке С++ средствами стандартной библиотеки

 

В любой программе, кроме операторов языка, используются средства различных библиотек, включаемых в интегрированную среду разработки. Стандартную библиотеку языка С++ можно разделить на две части:

– функции, макросы, типы и константы, унаследованные из библиотеки языка С;

– стандартные классы и другие средства языка С++.

Стандартные классы языка С++ можно разбить на следующие группы:

Потоковые классы для управления потоками данных между оперативной памятью и внешними устройствами (дисками, клавиатурой, экраном монитора), а также в пределах оперативной памяти.

Строковый класс для удобной и защищенной от ошибок работы с символьными строками.

Контейнерные классы, алгоритмы и итераторы. Контейнерные классы реализуют наиболее распространенные структуры для хранения данных – списки, вектора, множества и др. В состав стандартной библиотеки входят также алгоритмы, использующие и преобразующие контейнеры. Итераторы обеспечивают унифицированный доступ к элементам контейнерных классов.

Математические классы для эффективной обработки массивов с плавающей точкой и комплексных данных.

Диагностические классы для динамической идентификации типов и объектно-ориентированной обработки ошибок.

Остальные классы – для динамического распределения памяти, адаптации к локальным особенностям и т.д.

Часть стандартной библиотеки, в которую входят контейнерные классы, алгоритмы и итераторы, называют стандартной библиотекой шаблонов (Standart Template library, STL).

Рассмотрим средства ввода/вывода языка С++, основанные на использовании потоковых классов стандартной библиотеки языка С++.

Поток – понятие, относящееся к переносу данных от источника к приемнику. Потоки языка С++ обеспечивают надежную работу со стандартными и определенными пользователем типами данных, а также единообразный и понятный синтаксис.

Чтение данных из потока называется извлечением их из потока, вывод в поток – помещением или включением данных в поток. Поток определяется как последовательность байтов и не зависит от конкретного устройства, с которым выполняется обмен.

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

Стандартные потоки предназначены для передачи данных от клавиатуры и на экран дисплея, факловые потоки – для обмена информацией с файлами на магнитном диске, а строковые потоки – для работы с массивами символов в ОП.

Для поддержки потоков библиотека языка С++ содержим иерархию классов, построенную на основе двух базовых классов ios и streambuf. Класс ios содержит общие для ввода-вывода поля и методы, класс streambuf обеспечивает буферизацию потоков и их взаимодействие с физическими устройствами. От этих классов наследуется класс istream для входных потоков и класс ostream – для выходных. Эти классы являются базовыми для класса iostream, реализующего двунаправленные потоки. Далее в иерархии классов располагаются файловые и строковые потоки.

Основным преимуществом потоков по сравнению со стандартными функциями ввода-вывода языка Си, являются контроль типов, а так же расширяемость, то есть возможность работать с типами, определенными пользователем. Язык С++ не определяет ввод-вывод, а предоставляет широкий набор средств для реализации ввода-вывода. Ввод-вывод в языке С++ – это широкое использование перегрузки операций “<<” и “>>” класса iostream.

Ввод-вывод встроенных (стандартных) типов поддерживается соответствующими классами и объектами и, в частности, четырьмя предопределенными объектами: cin, cout, cerr и clog. Например, оператор cout <<х; посылает значение переменной х в объект cout класса ostream для вывода. Перегруженный метод operator << возвращает ссылку на объект ostream, для которого он был вызван. Поэтому к результату операции вывода можно еще раз применить операцию вывода, т.е. несколько операций вывода можно объединить в цепочку:

#i nclude < iostream.h >

int x;

cout <<”х=“<<х<<”\n”;

 

Учитывая, что операция “<<” имеет порядок вычислений слева-направо, такая запись будет интерпретироваться как

((cout.operator <<(“х=”)). operator <<(x)). operator <<(“\n”);

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

Аналогично выводу в языке С++ определяется и ввод. С вводом связан класс istream, в котором определена перегруженная операция “>>” для стандартных типов. Метод operator>> также возвращает ссылку на объект класса istream, и, значит, операции ввода можно также связывать в цепочку при вводе, например, трех аргументов:

((cin.operator >>(x)). operator >>(y)). operator >>(z);

Выбор конкретной операции ввода или вывода определяется каждый раз типом вводимого или выводимого данного.

Наряду со встроенными типами язык С++ позволяет определять новые типы (типы, определяемые пользователем). Для этого нужно перегрузить операции “<<” и “>>” для каждого пользовательского типа с использованием перегружаемой функции. Перегружающий метод для операции “<<” или “>>” обязательно должен быть дружественным классу, а не членом класса, потому что операнды операции из различных классов!

 

 

Приведем пример, иллюстрирующий детали перегрузки операций ввода/вывода.

сlass Complex // Класс - Комплексное число

{ int real, image;

public:

Complex (int re, int im) {real=re; image=im;}

f riend ostream & operator <<(ostream &, const Complex &);

friend istream & operator >>(istream &, Complex &);

};

ostream & operator <<(ostream & obj_out, const Complex & val_out)

{ return obj_out<<val_out.real<<”i”<<val_out.image<< endl; }

 

// obj_out – объект вывода, val_out – выводимое значение

 

// Перегрузка операции “>>” для ввода.

istream & operator >>(istream & obj_in, Complex & val_in)

{ obj_in>>val_in.real>>val_in.image;

if (!obj_in) { cout <<”\n Ошибка ввода”<< endl; exit (1); }

return 0;

}

int main (void)

{ Complex obj(12,21);

cout <<”Значение объекта:”<<obj;

cout <<”\n Введите комплексное число:”;

cin >>obj;

cout <<”\n Значение объекта obj=”<<obj;

return 0;

}

 

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

Потоковые классы содержат средства, позволяющие ввести или вывести данные в той или иной системе счисления с различной точностью. Выводимые данные можно прижимать к левому или правому концу поля вывода. Средства форматированного ввода-вывода позволяют управлять и другими деталями формата ввода-вывода. Одним из наиболее удобных способов реализации указанных возможностей является использование манипуляторов.

Манипуляторы используют перегружаемые методы, что упрощает кодирование форматированного ввода-вывода. Манипуляторы можно вставлять в цепочки ввода-вывода с помощью операций “>>” и “<<”. Манипуляторы бывают параметризованными, т.е. записываются в виде вызова функции с одним аргументом, и простыми, т.е. когда после имени манипулятора круглые скобки с аргументом отсутствуют. Для использования параметризованных манипуляторов в программу необходимо включить файл < iomanip.h >.

 

Основная литература – 5 [Гл. 11, 379–430], 6 [Гл. 5, 114–135], 8 [Гл. 8, 239–297]

 

Контрольные вопросы

1. Как определить, когда использовать перегруженные операции ввода “>>” и вывода “<<”, а когда другие методы классов потока?

2. Какие отличия между cerr и clog?

3. Что такое перегруженный оператор ввода и как он работает?

4. Что такое перегруженный оператор вывода и как он работает?

5. Какое значение возвращает перегруженный оператор вывода?



Поделиться:


Последнее изменение этой страницы: 2016-12-13; просмотров: 386; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.149.229.253 (0.074 с.)