Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Класс - (обобщенный) структурный тип.
Класс – это набор компонентов возможно разного типа. Способ группировки аналогичен записям/структурам, но
Поля - компоненты-данные класса, они задают способ представления значений этого типа. Методы - компоненты-операции класса, они задают процедуры и функции для работы с такими значениями.
Классы и модули. Классы можно использовать, не использую модули, и наоборот. Однако наилучших результатов удается добиться, только продуманно комбинируя возможности классов и модулей. В контексте именно такого использования мы и будем рассматривать аппарат классов. Основные рекомендации общего характера – определения классов, предназначенных «для использования другими», оформлять как интерфейсные инструменты подходящих модулей, а реализацию методов и определения классов (и других типов), предназначенных «для внутреннего пользования», оформлять как инкапсулированные инструменты этих модулей. При этом, используя секции классов можно (и нужно) дополнительно управлять степенью инкапсуляции компонентов класса (повышать защищенность). В модуле реализация методов класса отделена от определения класса, поэтому в заголовке описания метода (процедуры-функции) имя метода уточняется именем класса: § В Object Pascal 2: ИмяКласса. § В C++: ИмяКласса:: Если процедура или функция описана в модуле без уточнения именем класса, то она трактуется как обычная процедура-функция модуля, никак не связанная ни с каким классом (не трактуется как метод какого-либо класса). Класс можно объявить как локальный тип данных, например в процедуре или функции. Но оформление локального класса должно удовлетворять ряду требований. Локальные классы в этом курсе не рассматриваются. Описание переменных типа класс (как всегда) :
Переменные типа класс расширяют семантику понятия «переменная»: ¨ Компоненты такой переменной хранят не только данные, но и информацию об операциях с этими данными, кроме того компоненты такой переменной могут быть инкапсулированы (не видимы для «посторонних»). ¨ Переменные типа класс – это специальный вид динамических переменных:
§ переменные типа класс явно создаются и уничтожаются в периоде выполнения программы, для этого используются конструкторы и деструкторы. Конструкторы и деструкторы – это методы класса, нагруженные дополнительной специальной семантикой.
Ø Вариант 4. Динамическая реализация стеков и использование классов и модулей. Чисто технически новая реализация очень близка к ранее рассмотренной «Вариант 2», поэтому на следующей странице они обе представлены для визуального сравнения. В новой реализации решены вышерассмотренные проблемы: ¨ Новые инструменты позволяют работать одновременно с любым числом стеков - § теперь можно описать (и создать) переменные типа стек: VAR OStack1, OStack2: CStack; BEGIN... OStack1: =CStack.MakeNull;... OStack2: =CStack.MakeNull;... § операции теперь являются составной частью каждой переменной типа CStack, соответственно они и применяются свои для каждой переменной: y1: =OStack1.Top; OStack1.Pop;... y2: =OStack2.Top; OStack2.Pop;... ¨ «Уши» внутреннего представления стека «торчат» в секции INTERFACE, но «вытащить за эти уши» компоненты внутреннего представления стека и испортить их, уже возможности нет - само хранилище стека Stack защищено и недоступно извне. 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 PElement=^TElement; TElement= RECORD VElem: UVal.TVal; Next: PElement END; TStack= PElement; VAR Stack: TStack;
FUNCTION Empty: BOOLEAN; BEGIN Empty: =(Stack=NIL) END; PROCEDURE Push(xPrm: UVal.TVal); VAR p: PElement; BEGIN NEW(p); p^.VElem: =xPrm; p^.Next: =Stack; Stack: =p END; PROCEDURE Pop; VAR xStack: PElement; BEGIN IF Stack=NIL THEN {недопустима - стек пустой} ErrStack: =-2 ELSE BEGIN xStack: =Stack^.Next; Dispose(Stack); Stack: =xStack END END; FUNCTION Top; BEGIN IF Stack=NIL THEN {недопустима - стек пустой} ErrStack: =-2 ELSE Top: =Stack^.VElem END; PROCEDURE WriteAll; VAR p: PElement; BEGIN p: =Stack; WHILE p< > NIL DO BEGIN WriteElement(Stack^.VElem); p: =p^.Next END END; INITIALIZATION Stack: =NIL; ErrStack: =0 END. program Project1; uses UVal in 'UVal.pas', UStack in 'UStack.pas'; VAR Vh, Vih: FILE OF CHAR; x, y: CHAR; begin RESET(Vh); REWRITE(Vih);
WHILE NOT EOF(Vh) DO BEGIN READ(Vh, x); CASE x OF '(':; '+', '-', '*', '/': UStack.Push(x); ')': BEGIN y: =UStack.Top; WRITE(Vih, y); UStack.Pop END; ELSE {'a'..'z'} WRITE(Vih, x); END END; CloseFile(Vh); CloseFile(Vih) end. UNIT UStack; INTERFACE USES UVal; TYPE PElement=^TElement; TElement= RECORD VElem: UVal.TVal; Next: PElement END; TStack= PElement; CStack= CLASS PRIVATE Stack: TStack; PUBLIC ErrStack: INTEGER {Код ошибки}; FUNCTION Empty: BOOLEAN {Проверить на пустоту}; PROCEDURE Push(xPrm: UVal.TVal){Добавить, положить в стек}; PROCEDURE Pop {Удалить, вытолкнуть из стека}; FUNCTION Top: UVal.TVal {Посмотреть вершину}; PROCEDURE WriteAll {Вывести все элементы стека}; CONSTRUCTOR MakeNull {Создать пустой стек}; END; IMPLEMENTATION FUNCTION CStack.Empty: BOOLEAN; BEGIN Empty: =(Stack=NIL) END; PROCEDURE CStack.Push(xPrm: UVal.TVal); VAR p: PElement; BEGIN NEW(p); p^.VElem: =xPrm; p^.Next: =Stack; Stack: =p END; PROCEDURE CStack.Pop; VAR xStack: PElement; BEGIN IF Stack=NIL THEN {недопустима - стек пустой} ErrStack: =-2 ELSE BEGIN xStack: =Stack^.Next; Dispose(Stack); Stack: =xStack END END; FUNCTION CStack.Top: UVal.TVal; BEGIN IF Stack=NIL THEN {недопустима - стек пустой} ErrStack: =-2 ELSE Top: =Stack^.VElem END; PROCEDURE CStack.WriteAll; VAR p: PElement; BEGIN p: =Stack; WHILE p< > NIL DO BEGIN WriteElement(Stack^.VElem); p: =p^.Next END END; CONSTRUCTOR CStack.MakeNull; BEGIN Stack: =NIL; ErrStack: =0 END; END. program Project1; uses UVal in 'UVal.pas', UStack in 'UStack.pas'; VAR Vh, Vih: FILE OF CHAR; x, y: CHAR; OStack: CStack; begin RESET(Vh); REWRITE(Vih); OStack: =UStack.CStack.MakeNull; WHILE NOT EOF(Vh) DO BEGIN READ(Vh, x); CASE x OF '(':; '+', '-', '*', '/': OStack.Push(x); ')': BEGIN y: =OStack.Top; WRITE(Vih, y); OStack.Pop END; ELSE {'a'..'z'} WRITE(Vih, x); END END; CloseFile(Vh); CloseFile(Vih) end. PROGRAM\Prg3d\Project1.dpr Файл 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; //Код ошибки struct TElement {TVal VElem; TElement* Next; }; static TElement* Stack;
bool Empty() //Проверить на пустоту {return (Stack==NULL); } void Push(TVal xPrm) //Добавить, положить в стек {TElement* p; p=new(TElement); p-> VElem=xPrm; p-> Next=Stack; Stack=p; } void Pop() //Удалить, вытолкнуть из стека {TElement* xStack; if(Stack==NULL) ErrStack=-2; //недопустима - стек пустой else{ xStack=Stack-> Next; delete(Stack); Stack=xStack; }} TVal Top() //Посмотреть вершину {if(Stack==NULL) ErrStack=-2; //недопустима - стек пустой else return Stack-> VElem; } void WriteAll() //Вывести все элементы стека {TElement* p; p=Stack; while(p! =NULL){ WriteElement(Stack-> VElem); p=p-> Next; }} void MakeNull() //Создать пустой стек {Stack=NULL; ErrStack=0; } Файл prg3b.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); switch (x) { case '(': break; case '+': case '-': case '*': case '/': Push(x); break; case ')': Vih< < Top(); Pop(); break; default: /*'a'..'z'*/ Vih< < x; }} Vh.close(); Vih.close(); } Файл UStack.h: struct TElement {TVal VElem; TElement* Next; }; class CStack{ private: TElement* Stack; public: int ErrStack; //Код ошибки bool Empty(); //Проверить на пустоту void Push(TVal xPrm); //Добавить, положить в стек void Pop(); //Удалить, вытолкнуть из стека TVal Top(); //Посмотреть вершину void WriteAll(); //Вывести все элементы стека CStack(); //MakeNull - Создать пустой стек }; Файл UStack.cpp: #include " UVal.h" #include " UStack.h" bool CStack:: Empty() //Проверить на пустоту {return (Stack==NULL); } void CStack:: Push(TVal xPrm) //Добавить, положить в стек {TElement* p; p=new(TElement); p-> VElem=xPrm; p-> Next=Stack; Stack=p; } void CStack:: Pop() //Удалить, вытолкнуть из стека {TElement* xStack; if(Stack==NULL) ErrStack=-2; //недопустима - стек пустой else{ xStack=Stack-> Next; delete(Stack); Stack=xStack; }} TVal CStack:: Top() //Посмотреть вершину {if(Stack==NULL) ErrStack=-2; //недопустима - стек пустой else return Stack-> VElem; } void CStack:: WriteAll() //Вывести все элементы стека {TElement* p; p=Stack; while(p! =NULL){ WriteElement(Stack-> VElem); p=p-> Next; }} CStack:: CStack() //MakeNull - Создать пустой стек {Stack=NULL; ErrStack=0; } Файл prg3d.cpp: #include " UVal.h" #include " UStack.h" main(){ifstream Vh/*входной текст*/; ofstream Vih/*выходной текст*/; char x/*текущий символ*/, y; CStack OStack; Vh.open(" VhPrg3.TXT"); Vih.open(" VihPrg3.TXT"); //OStack=CStack(); while(Vh.peek()! =EOF){ Vh.get(x); switch (x) { case '(': break; case '+': case '-': case '*': case '/': OStack.Push(x); break; case ')': Vih< < OStack.Top(); OStack.Pop(); break; default: /*'a'..'z'*/ Vih< < x; }} Vh.close(); Vih.close(); } PROGRAM\C(C++)\prg3d\prg3d.dsw Реализация очередей. Ø Вариант 1. Статическая реализация очередей. Также как в случае статической реализации стека, используем вектор для представления очереди. Также как и в задаче о порождении обобщенно-периодичной последовательности мы столкнемся с «неприятностью» - при каждом удалении первого компонента очереди придется передвигать все остальные, поэтому «замкнем вектор в кольцо»(*). Поскольку операции добавления-удаления (с разных концов) могут выполняться в (почти) любом порядке, придется хранить позицию как первого (Front), так и последнего (Rear) компонента очереди. CONST CMaxL=1000; TYPE... RECORD Elem: ARRAY[1..CMaxL] OF UVal.TVal; Front, Rear: 0..CMaxL END; В итоге все получится естественно: удаление - сдвиг Front вперед (по кольцу по часовой стрелке), добавление - сдвиг Rear вперед (по кольцу). Однако возникнет одна двусмысленная ситуация - что означает нижеприведенное положение Front и Rear: очередь максимальной длины (Front..Rear по часовой стрелке) или пустую очередь? Устранить эту двусмысленность можно, не допуская того чтобы «Rear мог догнать Front», т.е. ограничив максимальную длину очереди величиной строго меньшей, чем длина представляющего вектора. PROGRAM\Prg4d0\Project1.dpr Ø Вариант 2. Динамическая реализация очередей. PROGRAM\PRG4D2\Project1.dpr PROGRAM\C(c++)\prg4d2\prg4d.dsw PROGRAM\Prg4d\Project1.dpr PROGRAM\C(c++)\PRG4D\prg4d.dsw Еще раз вернемся к общим рассуждениям о динамической памяти и последовательном доступе к ее компонентам. Внимательнее рассмотрим операциональные возможности различных видов динамической памяти.
|