Опубликован: 10.10.2006 | Доступ: свободный | Студентов: 6135 / 468 | Оценка: 4.26 / 3.88 | Длительность: 31:30:00
Лекция 13:

Проектирование библиотек

< Лекция 12 || Лекция 13: 1234567891011

13.4 Узловые классы

В действительности иерархия классов строится, исходя из совсем другой концепции производных классов, чем концепция интерфейс-реализация, которая использовалась для абстрактных типов. Класс рассматривается как фундамент строения. Но даже, если в основании находится абстрактный класс, он допускает некоторое представление в программе и сам предоставляет для производных классов какие-то полезные функции. Примерами узловых классов могут служить классы rectangle ( \S 6.4.2) и satellite ( \S 6.5.1). Обычно в иерархии класс представляет некоторое общее понятие, а производные классы представляют конкретные варианты этого понятия. Узловой класс является неотъемлемой частью иерархии классов. Он пользуется сервисом, представляемым базовыми классами, сам обеспечивает определенный сервис и предоставляет виртуальные функции и (или) защищенный интерфейс, чтобы позволить дальнейшую детализацию своих операций в производных классах.

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

class dialog_box : public window {
   // ...
public:
   dialog_box(const char* ...); // заканчивающийся нулем список
        // обозначений клавиш
   // ...
virtual int ask();
           };

Здесь важную роль играет функция ask() и конструктор, с помощью которого программист указывает используемые клавиши и задает их числовые значения. Функция ask() изображает на экране окно и возвращает номер нажатой в ответ клавиши. Можно представить такой вариант использования:

void user()
{
  for (;;) {
      // какие-то команды

      dialog_box cont("continue",
          "try again",
          "abort",
          (char*) 0);
      switch (cont.ask()) {
      case 0:  return;
      case 1:  break;
      case 2:  abort();
      }
    }
  }

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

Пользователь класса dialog_box ( а не только создатель этого класса) рассчитывает на сервис, представляемый его базовыми классами. В рассматриваемом примере предполагается, что существует некоторое стандартное размещение нового окна на экране. Если пользователь захочет управлять размещением окна, базовый для dialog_box класс window (окно) должен предоставлять такую возможность, например:

dialog_box cont("continue","try again","abort",(char*)0);
cont.move(some_point);

Здесь функция движения окна move() рассчитывает на определенные функции базовых классов.

Сам класс dialog_box является хорошим кандидатом для построения производных классов. Например, вполне разумно иметь такое окно, в котором, кроме нажатия клавиши или ввода с мышью, можно задавать строку символов (скажем, имя файла). Такое окно dbox_w_str строится как производный класс от простого окна dialog_box:

class dbox_w_str : public dialog_box {
    // ...
public:
   dbox_w_str (
    const char* sl,  // строка запроса пользователю
    const char* ...  // список обозначений клавиш
   );
   int ask();
   virtual char* get_string();
   //...
};

Функция get_string() является той операцией, с помощью которой программист получает заданную пользователем строку. Функция ask() из класса dbox_w_str гарантирует, что строка введена правильно, а если пользователь не стал вводить строку, то тогда в программу возвращается соответствующее значение (0).

void user2()
{
  // ...
  dbox_w_str file_name("please enter file name",
           "done",
           (char*)0);
  file_name.ask();
  char* p = file_name.get_string();
  if (p) {
     // используем имя файла
  }
  else {
    // имя файла не задано
  }
  //
}

Подведем итог - узловой класс должен:

  1. рассчитывать на свои базовые классы как для их реализации, так и для представления сервиса пользователям этих классов;
  2. представлять более полный интерфейс (т.е. интерфейс с большим числом функций-членов) пользователям, чем базовые классы;
  3. основывать в первую очередь (но не исключительно) свой общий интерфейс на виртуальных функциях;
  4. зависеть от всех своих (прямых и косвенных) базовых классов;
  5. иметь смысл только в контексте своих базовых классов;
  6. служить базовым классом для построения производных классов;
  7. воплощаться в объекте.

Не все, но многие, узловые классы будут удовлетворять условиям 1, 2, 6 и 7. Класс, который не удовлетворяет условию 6, походит на конкретный тип и может быть назван конкретным узловым классом. Класс, который не удовлетворяет условию 7, походит на абстрактный тип и может быть назван абстрактным узловым классом. У многих узловых классов есть защищенные члены, чтобы предоставить для производных классов менее ограниченный интерфейс.

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

< Лекция 12 || Лекция 13: 1234567891011
Дарья Федотова
Дарья Федотова
Сергей Березовский
Сергей Березовский

В рамках проф. переподготовки по программе "Программирование"

Есть курсы, которые я уже прошел. Но войдя в курс я вижу, что они не зачтены (Язык Ассемблера и архитектура ЭВМ, Программирование на С++ для профессионалов). Это как?

Станислав Мешавкин
Станислав Мешавкин
Россия, г. Заречный
Елена Маслова
Елена Маслова
Россия, Новокузнецк, Сибирский государственный индустриальный университет, 2010