Иерархии классов
Рассмотрим моделирование транспортного потока в городе, цель которогодостаточно точно определить время, требующееся, чтобы аварийные движущиесясредства достигли пункта назначения. Очевидно, нам надо иметьпредставления легковых и грузовых машин, машин скорой помощи,всевозможных пожарных и полицейских машин, автобусов и т.п.Поскольку всякое понятие реального мира не существует изолированно,а соединено многочисленными связями с другими понятиями,возникает такое отношение как наследование. Не разобравшись в понятияхи их взаимных связях, мы не в состоянии постичь никакое отдельноепонятие. Также и модель, если не отражает отношения междупонятиями, не может адекватно представлять сами понятия. Итак, внашей программе нужны классы для представления понятий, но этогонедостаточно. Нам нужны способы представления отношений между классами.Наследование является мощным способом прямого представленияиерархических отношений. В нашем примере, мы, по всей видимости,сочли бы аварийные средства специальными движущимися средствамии, помимо этого, выделили бы средства, представленные легковыми игрузовыми машинами. Тогда иерархия классов приобрела бы такой вид: движущееся средство легковая машина аварийное средство грузовая машинаполицейская машина машина скорой помощи пожарная машинамашина с выдвижной лестницейЗдесь класс 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) - прокручивание информации в окне.