Язык программирования C++. Вводный курс


Альтернативная иерархия классов - часть 2


// ошибка: отсутствует конструктор класса AndQuery

AndQuery proust( new NameQuery( "marcel" ),

                 new NameQuery( "proust " ));

то компилятор выдаст сообщение об ошибке: в классе AndQuery нет конструктора, готового принять два аргумента.

Мы предположили, что AndQuery и OrQuery

наследуют конструктор BinaryQuery

точно так же, как они наследуют функции-члены lop() и rop(). Однако производный класс не наследует конструкторов базового. (Это могло бы привести к ошибкам, связанным с неинициализированными членами производного класса. Представьте, что будет, если в AndQuery добавить пару членов, не являющихся объектами классов: унаследованный конструктор базового класса для инициализации объекта производного AndQuery

применять уже нельзя. Однако программист может этого не осознавать. Ошибка проявится не при конструировании объекта AndQuery, а позже, при его использовании. Кстати говоря, перегруженные операторы new и delete наследуются, что иногда приводит к аналогичным проблемам.)

Каждый производный класс должен предоставлять собственный набор конструкторов. В случае классов AndQuery и OrQuery

единственная цель конструкторов – обеспечить интерфейс для передачи двух своих операндов конструктору BinaryQuery. Так выглядит исправленная реализация:

// правильно: эти определения классов корректны

 

class OrQuery : public BinaryQuery {

public:

   OrQuery( Query *lop, Query *rop )

          : BinaryQuery( lop, rop ) {}

 

   virtual void eval();

};

 

class AndQuery : public BinaryQuery {

public:

   AndQuery( Query *lop, Query *rop )

          : BinaryQuery( lop, rop ) {}

 

   virtual void eval();

};

Если мы еще раз взглянем на рис. 17.2, то увидим, что BinaryQuery – непосредственный базовый класс для AndQuery и OrQuery, а Query –для BinaryQuery. Таким образом, Query не является непосредственным базовым классом для AndQuery и OrQuery.

Конструктору производного класса разрешается напрямую вызывать только конструктор своего непосредственного предшественника в иерархии (виртуальное наследование является исключением из этого правила, да и из многих других тоже: см. раздел 18.5). Например, попытка включить конструктор Query в список инициализации членов объекта AndQuery

приведет к ошибке.

При определении объектов классов AndQuery и OrQuery

теперь вызываются три конструктора: для базового Query, для непосредственного базового класса BinaryQuery и для производного AndQuery или OrQuery. (Порядок вызова конструкторов базовых классов отражает обход дерева иерархии наследования в глубину.) Дополнительный уровень иерархии, связанный с BinaryQuery, практически не влияет на производительность, поскольку мы определили его конструкторы как встроенные.

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




Начало  Назад  Вперед



Книжный магазин