Процедурные типы

Begin

Begin

Begin

Begin

Var

Struct

{

char type [20];

int opt, rozn;

char comm[40];

} mon;

int kol = 0; // Количество записей в файле

while ( fgets (s, dl, fi) )

{

strncpy (mon.type, s, sizeof (mon.type) - 1); // Копирует не более n символов

mon.type[sizeof (mon.type) - 1] = ‘\0’;

mon.opt = atoi (&s[iOpt]); // Преобразует строку в целое число

mon.rozn = atoi (&s[iRozn]);

strncpy (mon.comm, &s[iComm], sizeof (mon.comm) );

fwrite (&mon, sizeof mon, 1, fo); // Запись одного блока длиной sizeof (mon)

kol++;

}

fclose (fi);

 

int i;

cin >> i; // Ввести номер записи (нумерация - с 0)

if( i >= kol) {cout << “Такая запись не существует”; return 1;}

fseek (fo, (sizeof mon)*i, SEEK_SET); // Уст-ка указателя файла на запись i от начала

fread (&mon, sizeof mon, 1, fo); // Чтение одного блока

cout << “mon.type “ << mon.type << “ opt “ << mon.opt

<< “ rozn “ << mon.rozn << endl; // Последний – символ перевода строки

fclose (fo);

return 0;

}

 

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

 

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

Описанные внутри блока идентификаторы локальны. Их об­ласть действия начинается в точке объявления и заканчивает­ся в конце блока, время жизни – до выхода из блока. Исключение – статические переменные, время жизни которых начинается при первом объявлении и продолжается до конца работы программы. Аналогичными свойствами обладают переменные, объявленные в заголовке оператора for, а также формальные параметры функции.

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

Элементы структур, объединений и классов действуют и видимы лишь в пределах класса. Они образуются при создании переменной данного класса и разрушаются при ее уничтожении (время жизни статических элементов класса постоянно!).

Каждая область действия неявно определяет пространство имен. Про­странство имен – это область, в пределах которой идентификатор должен быть уни­кальным. В разных пространствах имена могут совпадать, например:

struct sNode

{

int Node;

int i;

} Node;

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

Рассмотрим пространство глобальных имен. Функция автоматически видна во всех модулях программы. Для того чтобы сделать доступной в нескольких модулях константу или переменную, достаточно:

· определить ее в единственном модуле как глобальную;

· в других заинтересованных модулях объявить ее как внешнюю с помощью модификатора extern.

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

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

C++ позволяет задавать явное пространство имен(именованную область) – область опреде­ления имен как часть глобальной области – с помощью оператора namespace. Именованные области служат для логического группирования объявлений и ограничения доступа к ним. При использовании единственной глобальной области видимости возможны совпадения и конфликты имен. Объявление пространства имен имеет вид

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

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

namespace demo

{

int i = 1;

int k = 0;

void func1 (int);

void func2 (int) { /* ... */ }

}

namespace demo // Расширение

{

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

void funcl (double); // Перегрузка

void func2 (int); // Верно – повторное объявление

}

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

В объявлении именованной области могут присутствовать как объявления, так и определения. Часто в нее помещают только объявления имен, а определяют их позднее с помощью оператора доступа к области видимости ::. Например:

void demo::func1(int) { /* ... */}

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

Идентификаторы, объявленные внутри области, являются видимыми с момента объявле­ния. К ним можно явно обращаться с помощью имени области:

demo::i = 100;

demo::func2 (10);

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

using demo::i;

После этого можно использовать имя без явного указания области.

Если требуется сделать доступными все имена из некоторой области, использу­ется оператор using namespace:

using namespace demo;

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

namespace Department_of_Applied_Mathematics

{

using demo::i;

………………

}

Имена, объявленные явно или оператором using, имеют приоритет по отношению к именам, объявленным с помощью опера­тора using namespace (это имеет значение при включении нескольких именован­ных областей, содержащих совпадающие имена).

Короткие имена пространств имен могут войти в конфликт друг с другом, а длинные непрактичны при написании реального кода, поэтому разрешается вводить синонимы имен:

namespace DAM = Department_of_App1ied_Mathematics;

Многие элементы стандартной библиотеки определены в пространстве имен std. При этом, для обратной совместимости с языком C, имеются заголовочные файлы старого стиля (например, <math.h>), позволяющие работать без namespace, и новые (<cmath>), построенные на основе namespace.

i: integer;

d: double;

s: string[2];

 

procedureShowInteger(varx);

writeln(Integer(x));

end;

procedureShowDouble(varx);

writeln(Double(x));

end;

 

procedureShowString(varx);

writeln(String(x));

end;

 


i := 1;

ShowInteger(i); // Будет выведено: 1

ShowDouble(i); // Будет выведена абракадабра

 

ShowString(i); // Возможны катастрофические последствия!!!

 

readln;

end.

 


<Объявление типа «Процедура» > :: =

<Имя Типа> = procedure(<Список формальных параметров>) ;

<Объявление типа «Функция» > :: =

<Имя Типа> = function(<Список формальных параметров>): <Тип> ;


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

 

На деле переменные процедурных типов являются указателями. До инициализации они имеют непредсказуемое значение. Не следует надеяться, что это именно Nil. Ответственность за вызов процедуры, на которую «указывает» неинициализированная процедурная переменная, несёт программист.