Информационный сайт

 

Реклама
bulletinsite.net -> Книги на сайте -> Программисту -> Мизрохи С.В. -> "Turbo Pascal и объектно-ориентированное программирование" -> 78

Turbo Pascal и объектно-ориентированное программирование - Мизрохи С.В.

Мизрохи С.В. Turbo Pascal и объектно-ориентированное программирование — М.: Финансы и статистика , 1992. — 192 c.
ISBN 5-279-00903-2
Скачать (прямая ссылка): efektispolzc2000.djvu
Предыдущая << 1 .. 72 73 74 75 76 77 < 78 > 79 80 81 82 83 84 .. 105 >> Следующая

Ниже приведена разумная реализация функций-членов класса Stack в первом приближении. Как бывает во многих прототипах реализации (и, к сожалению, Даже в коммерческих программах), контроль ошибок здесь отсутствует, поскольку в мире прототипов, как известно, никогда ничего плохого не случается.
же влияет, вам необходимы виртуальные функции, а значит, вы будете использовать наследование.
Вот как мы могли бы определить реализацию класса Stack, использующую связные списки, предполагая, что объекты, помещаемые в стек, имеют тип Т:
class Stack { public:
Stack(); .
-Stack ();
void push (const T& object) ¦ T pop ();
bool empty() const; Il Пуст ли стек?
private:
struct StackNode { // Узел связного списка.
A T data; // Данные в этом узле.
StackNode *next; // Следующий узел в списке.
// Конструктор StackNode инициализирует оба поля. StackNode(const Т& newData, StackNode *nextNode) : data(newData), next(nextNode) {}
};
StackNode *top; Stack(const Stacks rhs) ; Stacks operator=(const Stacks rhs)
ные
і.
Наследование и ООП
Stack::Stack(): top(O) {} Il Инициализация вершины значением null.
void Stack::push(const T& object)
I
top = new StackNode (object, top)
}
Il Добавить новый узел 11 в начале списка.
If Запомнить верхний узел. // Запомнить данные узла.
// Удалить все в стеке.
// Получить указатель на вершину. // Перейти к следующему узлу. // Удалить предыдущую вершину.
T Stack::рор() {
StackNode *topOfStack = top; top = top->next; T data = topOfStack->data; delete topOfStack; return data;
}
Stack::-Stack() {
while (top) {
StackNode *toDie = top; top = top->next; delete toDie;
}
}
bool Stack:: empty () const { return top == 0; }
В этой реализации нет ничего, что могло бы привлечь внимание. Единственное, что представляет здесь интерес, - это возможность писать функции-члены, по существу не имея никакой информации о Т. (Вы только допускаете, что можете вызвать конструктор копирования Т, но, как объясняется в правиле 45, это достаточно разумное предположение.) Код, написанный вами для создания стека, удаления стека, вставки/извлечения объектов и определения того, пуст ли стек, остается неизменным вне зависимости от типа Т. За исключением предположения, что вы можете вызвать конструктор копирования Т, поведение стека вообще никак не зависит от Т. Это отличительный признак шаблонного класса: его поведение не связано с типом.
Превращение класса Stack в шаблон настолько элементарно, что это ни для кого не составит труда:
template<class Т> class Stack { };
IIB точности то же, что и выше.
IHo вернемся к нашим кошкам. Почему шаблоны не подойдут для кошек? Перечитайте спецификацию и обратите внимание на то, что «каждая порода кошек ест и спит присущим только ей неподражаемым способом». Это означает, что вам необходимо реализовать различное поведение для различных типов кошек. Вы не можете просто написать одну-единственную функцию, которая бы работала со всеми объектами: все, что можно сделать, - это определить интерфейс функции, которую должны реализовать все типы кошек. Способ, который позволяет задать только интерфейс функции, заключается в объявлении чисто виртуальной функции (см. правило 36):
Правило 41
жт
class Cat {
public:
virtual -Cat (); virtual void eat() = 0; virtual void sleep () = 0;
//См. правило 14. Il Все кошки едят. Il Все кошки спят.
};
Подклассы класса Cat (скажем, Siamese и Brit ishShortHairedTabby) должны, конечно, переопределять функции eat и sleep наследуемого интерфейса-class Siamese: public Cat { public:
void eat () ;
void sleep ();
Ну вот, теперь вы знаєте, почему класс Stack реализован с использованием шаблонов и почему это не подойдет для класса Cat. Вы также знаете, почему для класса Cat используется наследование. Остается единственный вопрос: почему наследование не подходит для класса stack? Чтобы понять это, попробуйте объявить базовый класс иерархии Stack - один класс, от которого будут наследовать все другие классы стеков:
class Stack { Il Стек чего угодно.
Теперь проблема очерчивается четко. Какой тип вы хотите объявить для чисто виртуальных функций push и pop? Помните, что каждый подкласс должен переобъявлять наследуемые виртуальные функции с аргументами точно такого же типа и с возвращаемым типом, совместимым с тем, который объявлен в базовом классе. К сожалению, Для помещения и извлечения объектов типа int потребуется стек с целыми числами, в то время как для объектов Cat необходим стек с объектами Cat. Как может класс Stack объявить свои чисто виртуальные функции таким образом, чтобы пользователи Могли создавать стеки как с int, так и с Cat? Печальная истина заключается в том, Что это невозможно, и поэтому для создания стеков наследование не подходит.
Но, предположим, вы достаточно изворотливы. Вероятно, вы думаете, что перехитрите компилятор, используя указатели с типом void*. Как оказывается, указатели на void вам тоже не помогут. Вы просто не сможете проигнорировать требование о том, чтобы объявления виртуальных функций в производных классах
Предыдущая << 1 .. 72 73 74 75 76 77 < 78 > 79 80 81 82 83 84 .. 105 >> Следующая
Реклама
Авторские права © 2009 AdsNet. Все права защищены.
Rambler's Top100