Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Открытое, закрытое и защищенное наследование



Открытое наследование называется еще наследованием типа. Производный класс в этом случае является подтипом базового; он замещает реализации всех функций-членов, специфичных для типа базового класса, и наследует общие для типа и подтипа функции. Можно сказать, что производный класс служит примером отношения “ЯВЛЯЕТСЯ”, т.е. предоставляет специализацию более общего базового класса. Медведь (Bear) является животным из зоопарка (ZooAnimal); аудиокнига (AudioBook) является предметом, выдаваемым читателям (LibraryLendingMaterial). Мы говорим, что Bear – это подтип ZooAnimal, равно как и Panda. Аналогично AudioBook – подтип LibBook (библиотечная книга), а оба они – подтипы LibraryLendingMaterial. В любом месте программы, где ожидается базовый тип, можно вместо него подставить открыто унаследованный от него подтип, и программа будет продолжать работать правильно (при условии, конечно, что подтип реализован корректно). Во всех приведенных выше примерах демонстрировалось именно наследование типа.

Закрытое наследование называют также наследованием реализации. Производный класс напрямую не поддерживает открытый интерфейс базового, но пользуется его реализацией, предоставляя свой собственный открытый интерфейс.

Чтобы показать, какие здесь возникают вопросы, реализуем класс PeekbackStack, который поддерживает выборку из стека с помощью метода peekback():

bool

PeekbackStack::

peekback( int index, type & value ) {... }

где value содержит элемент в позиции index, если peekback() вернула true. Если же peekback() возвращает false, то заданная аргументом index позиция некорректна и в value помещается элемент из вершины стека.

В реализации PeekbackStack возможны два типа ошибок:

· реализация абстракции PeekbackStack: некорректная реализация поведения класса;

· реализация представления данных: неправильное управление выделением и освобождением памяти, копированием объектов из стека и т.п.

Обычно стек реализуется либо как массив, либо как связанный список элементов (в стандартной библиотеке по умолчанию это делается на базе двусторонней очереди, хотя вместо нее можно использовать вектор, см. главу 6). Хотелось бы иметь гарантированно правильную (или, по крайней мере, хорошо протестированную и поддерживаемую) реализацию массива или списка, чтобы использовать ее в нашем классе PeekbackStack. Если она есть, то можно сосредоточиться на правильности поведения стека.

У нас есть класс IntArray, представленный в разделе 2.3 (мы временно откажемся от применения класса deque из стандартной библиотеки и от поддержки элементов, имеющих отличный от int тип). Вопрос, таким образом, заключается в том, как лучше всего воспользоваться классом IntArray в нашей реализации PeekbackStack. Можно задействовать механизм наследования. (Отметим, что для этого нам придется модифицировать IntArray, сделав его члены защищенными, а не закрытыми.) Реализация выглядела бы так:

#include " IntArray.h"

 

class PeekbackStack: public IntArray {

private:

   const int static bos = -1;

 

public:

   explicit PeekbackStack( int size )

    : IntArray( size ), _top( bos ) {}

 

   bool empty() const { return _top == bos; }

   bool full() const { return _top == size()-1; }

   int top() const { return _top; }

 

   int pop() {

    if ( empty() )

         /* î á ð à á î ò à ò ü î ø è á ê ó */;

    return _ia[ _top-- ];

   }

 

   void push( int value ) {

    if ( full() )

         /* î á ð à á î ò à ò ü î ø è á ê ó */;

    _ia[ ++_top ] = value;

   }

   bool peekback( int index, int & value ) const;

 

private:

    int _top;

};

 

inline bool

PeekbackStack::

peekback( int index, int & value ) const

{

   if ( empty() )

   /* î á ð à á î ò à ò ü î ø è á ê ó */;

 

   if ( index < 0 || index > _top )

{

  value = _ia[ _top ];

  return false;

   }

 

   value = _ia[ index ];

   return true;

}

К сожалению, программа, которая работает с нашим новым классом PeekbackStack, может неправильно использовать открытый интерфейс базового IntArray:

extern void swap( IntArray&, int, int );

PeekbackStack is( 1024 );

 

// í å ï ð å ä â è ä å í í î å î ø è á î ÷ í î å è ñ ï î ë ü ç î â à í è å PeekbackStack

swap(is, i, j);

is.sort();

is[0] = is[512];

Абстракция PeekbackStack должна обеспечить доступ к элементам стека по принципу “последним пришел, первым ушел”. Однако наличие дополнительного интерфейса IntArray не позволяет гарантировать такое поведение.

Проблема в том, что открытое наследование описывается как отношение “ЯВЛЯЕТСЯ”. Но PeekbackStack не является разновидностью массива IntArray, а лишь включает его как часть своей реализации. Открытый интерфейс IntArray не должен входить в открытый интерфейс PeekbackStack.

Закрытое наследование от базового класса представляет собой вид наследования, который нельзя описать в терминах подтипов. В производном классе открытый интерфейс базового становится закрытым. Все показанные выше примеры использования объекта PeekbackStack становятся допустимыми только внутри функций-членов и друзей производного класса.

В приведенном ранее определении PeekbackStack достаточно заменить слово public в списке базовых классов на private. Внутри же самого определения класса public и private следует оставить на своих местах:

class PeekbackStack: private IntArray {... };


Поделиться:



Последнее изменение этой страницы: 2019-04-09; Просмотров: 342; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.013 с.)
Главная | Случайная страница | Обратная связь