С++ для начинающих


Наследование и композиция


Реализация класса PeekbackStack с помощью закрытого наследования от IntArray работает, но необходимо ли это? Помогло ли нам наследование в данном случае? Нет.

Открытое наследование – это мощный механизм для поддержки отношения “ЯВЛЯЕТСЯ”. Однако реализация PeekbackStack по отношению к IntArray – пример отношения “СОДЕРЖИТ”. Класс PeekbackStack содержит класс IntArray как часть своей реализации. Отношение “СОДЕРЖИТ”, как правило, лучше поддерживается с помощью композиции, а не наследования. Для ее реализации надо один класс сделать членом другого. В нашем случае объект IntArray делается членом PeekbackStack. Вот реализация PeekbackStack на основе композиции:

class PeekbackStack {

private:

           const int static bos = -1;

public:

           explicit PeekbackStack( int size ) :

           stack( 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 stack[ _top-- ];

           }

           void push( int value ) {

                  if ( full() )

              /* обработать ошибку */ ;

                  stack[ ++_top ] = value;

           }

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

private:

            int _top;

      IntArray stack;

};

inline bool

PeekbackStack::

peekback( int index, int &value ) const

{

           if ( empty() )

        /* обработать ошибку */ ;

           if ( index < 0 || index > _top )

     {

                  value = stack[ _top ];

                  return false;

           }

           value = stack[ index ];

           return true;

}

Решая, следует ли использовать при проектировании класса с отношением “СОДЕРЖИТ” композицию или закрытое наследование, можно руководствоваться такими соображениями:

  • если мы хотим заместить какие-либо виртуальные функции базового класса, то должны закрыто наследовать ему;
  • если мы хотим разрешить нашему классу ссылаться на класс из иерархии типов, то должны использовать композицию по ссылке (мы подробно расскажем о ней в разделе 18.3.4);
  • если, как в случае с классом PeekbackStack, мы хотим воспользоваться готовой реализацией, то композиция по значению предпочтительнее наследования. Если требуется отложенное выделение памяти для объекта, то следует выбрать композицию по ссылке (с помощью указателя).


  • Содержание раздела