Наследование

 

Наследование в ООМ понимается примерно так же, как и в ООП. Если объявляете класс с2 прямым потомком класса с1, то класс с2 наследует все элементы класса с1: переменные, методы, карту состояний, локальные поведения, локальную структуру - и все изменения в с1 автоматически отражаются на с2. Для обозначения отношения классов с1 и с2, помимо терминов «предок-потомок», часто используют также термины «родитель-наследник», «базовый-производный» (класс), а также «суперкласс-подкласс» (superclass-subclass). В производном классе нельзя удалить элементы, унаследованные от базового класса.

Часто используется понятие косвенного наследования, когда экземпляры одних классов входят как элементы в определение другого класса. Например, блок-контейнер на рис. 10.1 является косвенным наследником классов CSinGenerator и CGain.

Целью наследования является модификация базового класса. Пусть, например, мы хотим создать усилитель с насыщением, статическая характеристика которого показана на рис. 10.4.

Естественно строить описание этого специального усилителя на базе обычного линейного усилителя и сделать новый класс CSaturation прямым наследником класса CGain. Имеются два пути модификации.

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

 

Рис. 10.4

 

Добавим две новые переменные Хmin=LowerLimit/K и Хmax=UpperLimit/K, а также введем в карту состояний блока два новых узла и четыре перехода, как показано на рис. 10.5.

 

 

Рис. 10.5

 

Новый блок ведет себя в линейной зоне как предок, а вне нее - своим особым образом. Аналогично можно добавить новые локальные устройства и связи, процедуры и функции, анимационные отображения.

block class CSaturation extends CGain {

parameter Real UpperLimit = 1;

parameter Real LowerLimit = -UpperLimit;

statechart class Main {

Real Xmax = if K>0 then UpperLimit/K else 0;

Real Xmin = if K>0 then LowerLimit/K else 0;

initial state LinearZone {

do main;

};

state U_Saturation {

entry action {Y = UpperLimit }

};

state L_Saturation {

entry action {Y = LowerLimit}

};

transition from LinearZonetoU_Saturation when X>=Xmax;

transition from U_Saturation toLinearZonewhen X<Xmax;

transition from LinearZonetoL_Saturation when X<=Xmin;

transition from L_Saturation toLinearZonewhen X>Xmin;

}/*Main*/;

behavior {

do Main;

};

}/*CSaturation*/

Новые элементы в производном классе могут иметь те же идентификаторы, которые использованы в базовом. Например, в классе CSaturation можно ввести новую целую переменную с идентификатором K. Она будет скрывать или замещать в определении класса CSaturation вещественный параметр к классу CGain (например, в карте состояний Main будет использоваться целая переменная), а в определении базового класса (уравнении Е1) по-прежнему будет использоваться вещественный параметр K.

В определении класса CSaturation можно обратиться к параметру K по имени superK. Такая трактовка замещения элементов характерна для языков программирования. Однако, в языке Omola целая переменная K заменит вещественный параметр K и в базовом классе.

Второй путь состоит в переопределении элементов базового класса. Элемент производного класса с тем же идентификатором, что и некоторый элемент базового класса, замещает его в базовом классе не только в определении производного класса, но и в определении базового класса. Например, в приведенном примере можно не трогать карту состояний, а переопределить формулу Е1 в непрерывном поведении main, заменив ее на другую:

Y = ifХ<Хmin thenLowerLimit elseХ>Хmax thenUpperLimit elseK*X

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

block class CSaturation extends CGain {

parameter Real UpperLimit = 1;

parameter Real LowerLimit = -UpperLimit;

Real Xmax = if K>0 then UpperLimit/K else 0;

Real Xmin = if K>0 then LowerLimit/K else 0;

overrit equation classmain {

Y = ifХ<Хmin thenLowerLimit

elseХ>Хmax thenUpperLimit

elseK*X;

};

}/*CSaturation*/

В данном случае переопределили всю систему уравнений main. Чтобы переопределить именно нужное уравнение, оставив остальные (в данном случае их нет) без изменений, следует написать так:

overritmain.E1;

Y = ifХ<Хmin thenLowerLimit

elseХ>Хmax thenUpperLimit

elseK*X;

В этом варианте переопределяем только уравнение, помеченное как Е1. Ясно, что если уравнение не помечено, то никоим образом не сможем догадаться, какое уравнение переопределяем.