- •Абстрактные типы данных, модули и классы.
- •Implementation
- •Инкапсулированные (неимпортируемые) инструменты модуля:
- •Интерфейсные (экпортируемые) инструменты модуля:
- •Импорт инструментов модуля:
- •Статическая реализация динамической памяти типа «стек»
- •Implementation
- •Var Stack:tStack;
- •Procedure Push; var p:pElement; begin new(p);
Инкапсулированные (неимпортируемые) инструменты модуля:
Инструменты, локализованные в блоках описания функций, импортировать невозможно, они невидимы даже в своём модуле за пределами области их видимости.
Только максимальноглобальные инструменты модуля (программного файла) можно импортировать, т.е. только те, которые объявлены вне описаний функций.
Для инкапсуляции инструмента (защиты от импорта) в начале его объявления ставится ключевое слово static. Модификатор класса памяти static допустим только для переменных, констант и функций, т.е. защитить определение типа от импорта невозможно. Попытка импорта инкапсулированного инструмента пресекается на этапе редактирования межмодульных связей после трансляции всех модулей многомодульной программы.
Модификатор класса памяти static применим и к локальным переменным. Как показано в таблице 2 на предыдущей странице, воздействие модификатора static на глобальные и локальные переменные заметно различается. Для глобальных переменных – он сужает область видимости (но не изменяет период жизни), а для локальных – расширяет период жизни (но не изменяет область видимости). Локальные static-переменные - это что-то новое в дилемме локальные - глобальные. При выходе из своего блока, области видимости этой переменной, она не уничтожается, как это происходит с обычной локальной переменной, и сохраняет своё значение. А потому при повторном входе в свой блок восстанавливается её последнее значение от предыдущего входа в этот блок.
Интерфейсные (экпортируемые) инструменты модуля:
Импортировать можно любой максимальноглобальный инструмент модуля, не защищённый модификатором static в его объявлении.
Импорт инструментов модуля:
Импортирование оформляется в импортирующем модуле повторным объявлением инструмента, а точнее ссылкой на основное собственно объявление этого инструмента в экспортирующем модуле:
Импорт функции: включить (в импортирующий модуль) прототип этой функции. Можно в начало прототипа поставить ключевое слово extern, но этот модификатор класса памяти для функций устанавливается по умолчанию.
Импорт переменной: включить объявление этой переменной, но с модификатором extern (в начале объявления) и без инициализации.
Импорт константы: оформляется аналогично, но в определении константы обязательно опускается определяющая часть =значение
Импорт типа: оформляется полным повторным объявлением.
Повторные объявления – опасная штука, могут появиться расхождения в этих объявлениях и сопутствующие им недоразумения... Чтобы оградить программиста от технических проблем, сопутствующих повторным объявлениям, в С/С++ используется понятие «заголовочный h-файл» и директива препроцессорных средств #include:
В заголовочный h-файл включается весь импорт модуля.
#include ИмяФайлаОбрамлённое
Эта директива имеет следующий смысл: заменить текст директивы текстом файла, имя которого указано в директиве. Если параметр директивы задан в виде <ИмяФайла>, то файл ищется в предопределенном каталоге среды программирования, а если в виде строковой константы ”ИмяФайла” – то в текущем каталоге проекта. Директивы препроцессорных средств обрабатываются препроцессором до трансляции модуля.
Вариант 1. С/С++. Статическая реализация стека.
На следующей странице приведена С/С++-программа статической реализации стека вместе с выше рассмотренной Pascal-программой для визуального сравнения.
UNIT UVal; INTERFACE TYPE TVal= CHAR;
PROCEDURE WriteElement(xPrm:TVal);
CONST CMaxL=1000 {статическая реализация - размер стека
изначально ограничен};
IMPLEMENTATION
PROCEDURE WriteElement(xPrm:TVal); BEGIN WRITE(xPrm) END;
END.
UNIT UStack;
INTERFACE USES UVal;
FUNCTION Empty:BOOLEAN {Проверить на пустоту};
PROCEDURE Push(xPrm:UVal.TVal){Добавить, положить в стек};
PROCEDURE Pop {Удалить, вытолкнуть из стека};
FUNCTION Top:UVal.TVal {Посмотреть вершину};
PROCEDURE WriteAll {Вывести все элементы стека};
VAR ErrStack:INTEGER {Код ошибки};
IMPLEMENTATION
TYPE TStack= RECORD Elem: ARRAY[1..CMaxL] OF UVal.TVal;
Top: 0..CMaxL END;
VAR Stack: TStack;
FUNCTION Empty:BOOLEAN; BEGIN Empty:=(Stack.Top=0) END;
PROCEDURE Push(xPrm:UVal.TVal);
BEGIN IF Stack.Top=CMaxL THEN {переполнение} ErrStack:=-1
ELSE BEGIN Stack.Top:=Stack.Top+1;
Stack.Elem[Stack.Top]:=xPrm END END;
PROCEDURE Pop;
BEGIN IF Stack.Top=0 THEN {стек пустой} ErrStack:=-2
ELSE Stack.Top:=Stack.Top-1 END;
FUNCTION Top:UVal.TVal;
BEGIN IF Stack.Top=0 THEN {стек пустой} ErrStack:=-2
ELSE Top:=Stack.Elem[Stack.Top] END;
PROCEDURE WriteAll; VAR i:INTEGER; BEGIN
FOR i:=1 TO Stack.Top DO WriteElement(Stack.Elem[i]) END;
INITIALIZATION {Создать пустой стек} Stack.Top:=0; ErrStack:=0
END.
program Project1; uses UVal, UStack; LABEL 1;
VAR Vh,Vih: FILE OF CHAR; x,y: CHAR; begin RESET(Vh); REWRITE(Vih);
WHILE NOT EOF(Vh) DO BEGIN READ(Vh,x);
IF ErrStack<0 THEN BEGIN WRITE(’ErrStack=’,ErrStack); goto 1 END;
IF x='(' THEN ELSE
IF (x='+')OR(x='-')OR(x='*')OR(x='/') THEN UStack.Push(x) ELSE
IF x=')' THEN BEGIN y:=UStack.Top; WRITE(Vih,y); UStack.Pop END
ELSE {'a'..'z'} WRITE(Vih,x);
END; 1:end. PROGRAM\PRG3A\Project1.dpr
Файл UVal.h:
typedef char TVal; void WriteElement(TVal xPrm);
//extern const int CMaxL; // надо бы так, но... см. UStack.cpp
const int CMaxL=1000; // размер стека изначально ограничен
Файл UVal.cpp: #include "UVal.h"
//const int CMaxL=1000; // надо бы так, но... см. UVal.h
void WriteElement(TVal xPrm){cout<<xPrm;}
Файл UStack.h:
void MakeNull(); //Создать пустой стек
bool Empty(); //Проверить на пустоту
void Push(TVal xPrm); //Добавить, положить в стек
void Pop(); //Удалить, вытолкнуть из стека
TVal Top(); //Посмотреть вершину
void WriteAll(); //Вывести все элементы стека
extern int ErrStack; //Код ошибки
Файл UStack.cpp: #include "UVal.h"
int ErrStack; //Код ошибки
//!!! не разрешает массив с размером - внешняя константа:
typedef struct{TVal Elem[CMaxL]; int Top;} TStack;
static TStack Stack;
void MakeNull(){Stack.Top=-1; ErrStack=0;};
bool Empty(){return (Stack.Top==-1);}
void Push(TVal xPrm)
{if(Stack.Top==(CMaxL-1)) ErrStack=-1;//переполнение
else{ Stack.Top=Stack.Top+1; Stack.Elem[Stack.Top]=xPrm; }};
void Pop(){ if(Stack.Top==-1) ErrStack=-2; // стек пустой
else Stack.Top=Stack.Top-1; };
TVal Top(){ if(Stack.Top==-1) ErrStack=-2; // стек пустой
else return Stack.Elem[Stack.Top]; }
void WriteAll(){int i;
for(i=0;i<=Stack.Top;i++) WriteElement(Stack.Elem[i]);}
Файл PRG3A.cpp: #include "UVal.h"
#include "UStack.h"
main(){ ifstream Vh; ofstream Vih; char x,y;
Vh.open("VhPrg3.TXT"); Vih.open("VihPrg3.TXT"); MakeNull();
while(Vh.peek()!=EOF){ Vh.get(x);
if(ErrStack<0){ cout<<"ErrStack="<<ErrStack; goto m1;}
if(x=='(');else
if((x=='+')||(x=='-')||(x=='*')||(x=='/')) Push(x); else
if(x==')'){ Vih<<Top(); Pop();}
else /*'a'..'z'*/ Vih<<x;
} m1:;} PROGRAM\C(C++)\PRG3A\PRG3A.dsw