Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
С++ Страуструп.doc
Скачиваний:
4
Добавлен:
18.04.2019
Размер:
2.72 Mб
Скачать

12.2.2 Иерархии классов

Рассмотрим моделирование транспортного потока в городе, цель которого

достаточно точно определить время, требующееся, чтобы аварийные движущиеся

средства достигли пункта назначения. Очевидно, нам надо иметь

представления легковых и грузовых машин, машин скорой помощи,

всевозможных пожарных и полицейских машин, автобусов и т.п.

Поскольку всякое понятие реального мира не существует изолированно,

а соединено многочисленными связями с другими понятиями,

возникает такое отношение как наследование. Не разобравшись в понятиях

и их взаимных связях, мы не в состоянии постичь никакое отдельное

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

понятиями, не может адекватно представлять сами понятия. Итак, в

нашей программе нужны классы для представления понятий, но этого

недостаточно. Нам нужны способы представления отношений между классами.

Наследование является мощным способом прямого представления

иерархических отношений. В нашем примере, мы, по всей видимости,

сочли бы аварийные средства специальными движущимися средствами

и, помимо этого, выделили бы средства, представленные легковыми и

грузовыми машинами. Тогда иерархия классов приобрела бы такой вид:

движущееся средство

легковая машина аварийное средство грузовая машина

полицейская машина машина скорой помощи пожарная машина

машина с выдвижной лестницей

Здесь класс Emergency представляет всю информацию, необходимую для

моделирования аварийных движущихся средств, например: аварийная

машина может нарушать некоторые правила движения, она имеет

приоритет на перекрестках, находится под контролем диспетчера

и т.д.

На С++ это можно задать так:

class Vehicle { /*...*/ };

class Emergency { /* */ };

class Car : public Vehicle { /*...*/ };

class Truck : public Vehicle { /*...*/ };

class Police_car : public Car , public Emergency {

//...

};

class Ambulance : public Car , public Emergency {

//...

};

class Fire_engine : public Truck , Emergency {

//...

};

class Hook_and_ladder : public Fire_engine {

//...

};

Наследование - это отношение самого высокого порядка, которое прямо

представляется в С++ и используется преимущественно на ранних

этапах проектирования. Часто возникает проблема выбора: использовать

наследование для представления отношения или предпочесть ему

принадлежность. Рассмотрим другое определение понятия аварийного

средства: движущееся средство считается аварийным, если оно

несет соответствующий световой сигнал. Это позволит упростить

иерархию классов, заменив класс Emergency на член класса

Vehicle:

движущееся средство (Vehicle {eptr})

легковая машина (Car) грузовая машина (Truck)

полицейская машина (Police_car) машина скорой помощи (Ambulance)

пожарная машина (Fire_engine)

машина с выдвижной лестницей (Hook_and_ladder)

Теперь класс Emergency используется просто как член в тех классах,

которые представляют аварийные движущиеся средства:

class Emergency { /*...*/ };

class Vehicle { public: Emergency* eptr; /*...*/ };

class Car : public Vehicle { /*...*/ };

class Truck : public Vehicle { /*...*/ };

class Police_car : public Car { /*...*/ };

class Ambulance : public Car { /*...*/ };

class Fire_engine : public Truck { /*...*/ };

class Hook_and_ladder : public Fire_engine { /*...*/ };

Здесь движущееся средство считается аварийным, если Vehicle::eptr

не равно нулю. "Простые" легковые и грузовые машины инициализируются

Vehicle::eptr равным нулю, а для других Vehicle::eptr должно быть

установлено в ненулевое значение, например:

Car::Car() // конструктор Car

{

eptr = 0;

}

Police_car::Police_car() // конструктор Police_car

{

eptr = new Emergency;

}

Такие определения упрощают преобразование аварийного средства в

обычное и наоборот:

void f(Vehicle* p)

{

delete p->eptr;

p->eptr = 0; // больше нет аварийного движущегося средства

//...

p->eptr = new Emergency; // оно появилось снова

}

Так какой же вариант иерархии классов лучше? В общем случае ответ такой:

"Лучшей является программа, которая наиболее непосредственно отражает

реальный мир". Иными словами, при выборе модели мы должны стремиться

к большей ее"реальности", но с учетом неизбежных ограничений,

накладываемых требованиями простоты и эффективности. Поэтому,

несмотря на простоту преобразования обычного движущегося средства в

аварийное, второе решение представляется непрактичным.

Пожарные машины и машины скорой помощи - это

движущиеся средства специального назначения со специально

подготовленным персоналом, они действуют под управлением команд

диспетчера, требующих специального оборудования для связи. Такое

положение означает, что принадлежность к аварийным движущимся средствам -

это базовое понятие, которое для улучшения контроля типов и

применения различных программных средств должно быть прямо

представлено в программе. Если бы мы моделировали ситуацию, в которой

назначение движущихся средств не столь определенно,

скажем, ситуацию, в которой частный транспорт периодически используется

для доставки специального персонала к месту происшествия, а связь

обеспечивается с помощью портативных приемников, тогда мог бы

оказаться подходящим и другой способ моделирования системы.

Для тех, кто считает пример моделирования движения транспорта

экзотичным, имеет смысл сказать, что в процессе проектирования

почти постоянно возникает подобный выбор между наследованием

и принадлежностью. Аналогичный пример есть в $$12.2.5, где

описывается свиток (scrollbar) - прокручивание информации в окне.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]