Вход/Регистрация
Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ
вернуться

Майерс Скотт

Шрифт:

Это можно сделать с помощью using-объявлений:

class Base {

private:

int x;

public:

virtual void mf1 = 0;

virtual void mf1(int);

virtual void mf2;

void mf3;

void mf3(double);

...

};

class Derived: public Base {

public:

using Base::mf1; // обеспечить видимость всех (открытых) имен

using Base::mf3; // mf1 и mf3 из класса Base в классе Derived

virtual void mf1

void mf3;

void mf4;

...

};

Теперь наследование будет работать, как и ожидается.

Derived d;

int x;

...

d.mf1; // по-прежнему правильно, вызывается Derived::mf1

d.mf1(x); // теперь правильно, вызывается Base::mf1

d.mf2; // по-прежнему правильно, вызывается Base::mf2

d.mf3; // по-прежнему правильно, вызывается Derived::mf3

d.mf3(x); // теперь правильно, вызывается Base::mf3

Это означает, что если вы наследуете базовому классу с перегруженными функциями и хотите переопределить только некоторые из них, то должны включить using-объявление для каждого имени, иначе оно будет скрыто.

Можно представить себе ситуацию, когда вы не хотите наследовать все функции из базовых классов. При открытом наследовании такое никогда не должно происходить, так как это противоречит смыслу отношения «является» между базовым классом и производным от него. Вот почему using-объявление находится в секции public объявления производного класса; имена, которые открыты в базовом классе, должны оставаться открытыми и в открыто унаследованном от него. Но при закрытом наследовании (см. правило 39) такое желание иногда осмыслено. Например, предположим, что класс Derived закрыто наследует классу Base, и единственная версия mfl, которую Derived хочет унаследовать, – это та, что не принимает параметров. Using-объявление в этом случае не поможет, поскольку оно делает видимыми в производном классе все унаследованные функции с заданным именем. Здесь требуется другая техника – простая перенаправляющая функция:

class Base {

public:

virtual void mf1 = 0;

virtual void mf1(int);

... // как раньше

};

class Derived: private Base {

public:

virtual void mf1 // перенаправляющая функция

{ Base::mf1;} // неявно встроена (см. правило 30)

...

};

...

Derived d;

Int x;

d.mf1; // правильно, вызывается Derived::mf1

d.mf1(x); // ошибка! Base::mf1 скрыта

Другое применение встроенных перенаправляющих функций – обойти дефект в тех устаревших компиляторах, которые не поддерживают using-объявления для импорта унаследованных имен в область видимости производного класса.

Это все, что можно сказать о наследовании и сокрытии имен. Впрочем, когда наследование сочетается с шаблонами, возникает совсем другой вариант проблемы «сокрытия унаследованных имен». Все подробности, касающиеся шаблонов, см. в правиле 43.

Что следует помнить

• Имена в производных классах скрывают имена из базовых классов. При открытом наследовании это всегда нежелательно.

• Чтобы сделать скрытые имена видимыми, используйте using-объявления либо перенаправляющие функции.

Правило 34: Различайте наследование интерфейса и наследование реализации

Внешне простая идея открытого наследования при ближайшем рассмотрении оказывается состоящей из двух различных частей: наследования интерфейса функций и наследования их реализации. Различие между этими двумя видами наследования соответствует различию между объявлениями и определениями функций, обсуждавшемуся во введении к этой книге.

При разработке классов иногда требуется, чтобы производные классы наследовали только интерфейс (объявления) функций-членов. В других случаях необходимо, чтобы производные классы наследовали и интерфейс, и реализацию функций, но могли переопределять унаследованную реализацию. А иногда вам может понадобиться использование наследования интерфейса и реализации, но без возможности что-либо переопределять.

Чтобы лучше почувствовать различия между этими вариантами, рассмотрим иерархию классов для представления геометрических фигур в графическом приложении:

  • Читать дальше
  • 1
  • ...
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: