Практическая разработка средств объектно-ориентированного программирования в задачах защиты информации
Программная реализация стека на языке С++
В случае использования механизмов языка C, стратегия может быть следующей - мы объявляем набор операций для работы со стеком и заводим некоторую структуру для хранения его содержимого. Ниже приведен пример заголовочного файла для стека, а также файл модуля, где реализованы функции работы со стеком, объявленные в заголовке.
/* file simple_stack.h 7 #ifndef _SIMPLE_STACK_H #define _SIMPLE_STACK_H #define MAX_STACK_SIZE 200
typedef struct {top;* content [MAX_STACK_SIZE]; } SimpleStack;
/* returns -1 if overflow 7push (SimpleStack *pstack, void *pobj); /* returns NULL if empty 7* pop (SimpleStack *pstack); * allocateStack();freeStack (SimpleStack *pstack); #endif/*_SIMPLE_STACK_H */ /* file simple_stack.c */ #include <malloc.h> #include <stdlib.h> #include «simple_stack.h» * allocateStack() {* pstack = (SimpleStack*) malloc (sizeof (SimpleStack));>top = 0;pstack; } freeStack (SimpleStack *pstack) {(pstack); } push (SimpleStack *pstack, void *pobj) {(pstack->top < MAX_STACK_SIZE) {>content[(pstack->top)++] = pobj;0; } else {-1; /* overflow */ } } * pop (SimpleStack *pstack) {(pstack->top > 0) {pstack->content[- (pstack->top)]; } else { return NULL; /* underflow */ } }
Данная реализация имеет множество недостатков, хотя и может сгодиться для небольших программ. Главными являются следующие два: Данные экземпляров структуры не защищены от недобросовестного использования. Следующий код может непоправимо нарушить работу программы:
SimpleStack pStack = allocateStack(); pStack->top = -10;
Стек реализован в виде массива, и нет простого способа заменить его реализацию в программах, уже использующих данную версию. Мы можем существенно усовершенствовать наш стек, если воспользуемся средствами модульного программирования, имеющимися в языке С++.
// Файл advanced_stack.h // Усовершенствованный вариант стека, использующий // механизм модульности языка C++ #ifndef _ADVANCED_STACK_H #define _ADVANCED_STACK_H
// Таким образом мы определяем функциональный
// контракт модульной реализации стека namespace advanced_stack { struct Stack_impl;struct Stack_impl AdvancedStack;
// returns -1 if overflowpush (AdvancedStack *pstack, void *pobj); // returns NULL if empty* pop (AdvancedStack *pstack); * allocateStack();freeStack (AdvancedStack* pstack); } #endif // _ADVANCED_STACK_H
// Файл advanced_stack.cpp // Реализация контракта модульной реализации стека #include «advanced_stack.h»
namespace advanced_stack {int MAX_STACK_SIZE = 200;Stack_impl {top;* content [MAX_STACK_SIZE]; }; _impl* allocateStack() {_impl *pstack = new Stack_impl();>top = 0;pstack; } freeStack (Stack_impl *pstack) {pstack; } push (Stack_impl *pstack, void *pobj) {(pstack->top < MAX_STACK_SIZE) {>content[(pstack->top)++] = pobj;0; } else {-1; // overflow } } * pop (Stack_impl *pstack) {(pstack->top > 0) {pstack->content[- (pstack->top)]; } else { return 0; //underflow } } }
В данной реализации решены обе упомянутые выше проблемы. Примером использования модульной организации стека может стать следующая программа:
#include <stdio.h> #include «advanced_stack.h» main() {namespace advanced_stack;*pstack = allocateStack(); //pstack->top = 10; // Данная строка вызвала бы ошибку компиляции,*letters [3] = {«one», «two», «three»}; int i;(pstack, (void*) (letters[0]));(pstack, (void*) (letters[1]));(pstack, (void*) (letters[2]));(i = 0; i < 3; i++) {(«\n % s\n», (char*) pop(pstack)); } freeStack(pstack); }
Если в будущем потребуется заменить реализацию стека, то это можно сделать изменив реализацию структуры Stack_impl и функции работы с ней, реализованные в файле advanced_stack.cpp. Также можно объявить новое пространство имен (namespace), например dynamic_stack например, в котором будет реализован стек изменяемого размера. В прежней программе, использующей модульную реализацию стека, достаточно будет заменить строку using namespace advanced_stack; на строку namespace dynamic_stack;
Это можно сделать при условии, что новое пространство имен имеет контракт, совпадающий с предыдущим. Таким образом, мы вплотную подошли к идее объединения данных и кода, предназначенного для обработки этих данных, в одну концептуально целостную единицу. Следующим шагом является объектная реализация стека.
// Файл object_stack.h #ifndef _OBJECT_STACK_H
#define _OBJECT_STACK_H
// Объектная модель стека class ObjectStack {:const int MAX_STACK_SIZE;top;**content;: // Вместо allocateStack(…), используется конструктор ObjectStack(); // Вместо freeStack() используется деструктор ~ObjectStack(); int push (void* pobj); void* pop(); };
#endif // _OBJECT_STACK_H // Файл object_stack.cpp #include «object_stack.h»
// Реализация объектной модели стекаint ObjectStack:MAX_STACK_SIZE = 200; : ObjectStack() :top(0) {= new void*[MAX_STACK_SIZE]; } :~ObjectStack() {[] content; } * ObjectStack:pop() {(top > 0) {content[-top]; } else {0; // underflow } } ObjectStack:push (void* pobj) {(top < MAX_STACK_SIZE) {[top++] = pobj;0; } else { -1; // overflow } }
Примером использования такого стека может служить следующая программа:
int main() {*pstack = new ObjectStack();*letters [3]= {«one», «two», «three»}; int i; // Доступ к членам данным в принципе невозможен извне // функций-членов класса ObjectStack // pstack->top = -10; // Ошибка времени компиляции
pstack->push ((void*) letters[0]);>push ((void*) letters[1]);>push ((void*) letters[2]);(i= 0; i<3; i++) {(«\n % s\n», (char*) pstack->pop()); } delete pstack; }
Пользоваться такой реализацией стека гораздо удобней, кроме того, она надежней предыдущих. Код лаконичен и прост для понимания.
Воспользуйтесь поиском по сайту: ©2015 - 2025 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|