Бьерн Страуструп.
Язык программирования С++
343
//
обозначений клавиш
//
...
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()
Бьерн Страуструп.
Язык программирования С++
344
{
//
...
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: для трансляции своей программы пользователь узлового класса должен
включить описания всех его прямых и косвенных базовых классов, а также описания всех тех классов, от
которых, в свою очередь, зависят базовые классы. В этом узловой класс опять представляет контраст с
абстрактным типом. Пользователь абстрактного типа не зависит от всех классов, использующихся для
реализации типа и для трансляции своей программы не должен включать их описания.
Достарыңызбен бөлісу: