Для тех же целей мы можем применить закрытое (или защищенное) наследование (листинг 8.12).
Листинг 8.12. Специализация стека путем закрытого наследования
class StringStack: private TStack { public:
void push(string *s) { TStack::push(s); }
string *top() const { return (string *)TStack::top(); }
string *pop() { return (string *)TStack::pop(); }
bool empty() const { return TStack::empty(); }
}:
Проверка выполняется точно так же, как и в примере с открытым наследованием (см. листинг 8.10).
Чисто внешне разница заключается только в том, что мы заменили одно слово другим. Кроме того, в явном виде реализован метод empty (), чего мы не делали при открытом наследовании. Дело в том, что при закрытом наследовании все элементы класса-наследника становятся приватными и недоступными клиенту. Поэтому мы должны в наследнике либо реализовать нужные нам методы, либо открыть методы базового класса с помощью объявления us i ng (см. п. п. 7.3.3 в [1]). Обычное его применение связано с использованием пространств имен, однако и в классах такое объявление позволяет разрешить проблемы видимости. Синтаксис объявления using очень прост:
using <имя базового класса>::<имя в базовом классе>;
Например, мы можем реализовать стек для чисел типа double, закрыто унаследовав от класса TDeque. Тогда <имя базового класса> — это имя TDeque, а <имя в базовом классе> — это имя открываемого метода. Если в качестве вершины стека мы выберем начало дека, то реализация может быть такой, как показано в листинге 8.13.
Листинг 8.13. Использование закрытого наследования для реализации стека
class TStack: private TDeque
{ publ" с:
US- ng TDeque: :isEmpty; II проверка отсутствия элементов
US" ng TDeque: :push_front; II поместить элемент на вершину
US1 ng TDeque: :pop_front; II удалить элемент с вершины
US" ng TDeque: :begin; II получить доступ к элементу
US 1 ng TDeque: : size; II количество элементов в стеке
using TDeque: :i terator; II вообще-то обычно не нужен
В данном случае закрытое наследование позволяет нам ограничить в наследнике предоставляемую функциональность. Однако мы вынуждены открывать итератор, так как в базовом классе TDeque значение элемента предоставляет операция разыменования итератора. В частности, метод begin() выдает итератор. Можно, как мы делали ранее, упрятать всю работу с итераторами в явно реализованный метод top().
Использовать такой стек так же просто, как и реализованный непосредственно: TStack S;
TStack::iterator is; S.push_front(1); S.push_front(2); S.push_front(3); S.push_front(4); S.push_front(5); while (!S. isEmptyO)
{ is = S.beginO; cout << *is << ' ' ; S.pop_f ront(); }
На экране появится строка
5 4 3 2 1
Вспомним, что операция присваивания создается в любом классе, если не определена явно. Таким образом, при наследовании операция присваивания, создаваемая по умолчанию в производном классе, скрывает операцию присваивания базового класса. Однако использовав объявление usi ng, мы можем открыть операцию базового класса в производном класса — это делается так:
using Base::operator=;
|