Идиомы и стили С++ | страница 20



и operator||(), и всегда правильно задавайте возвращаемое значение операторов.

Шаг 14 - Двойная диспетчеризация. Продолжение.

В Шаге 4 мы говорили о двойной диспетчеризации. Она очень хорошо подходит при необходимости отображения одних объектов посредством других, но не только; она в общем применима, когда Вам нужно обрабатывать попарные (и более) взаимодействия объектов двух и более разных классов. Получается этакая табличка, на осях которой нарисованы классы, а в ячейках - функции их взаимодействия. Количество функций равно произведению столбцов и строк этой таблички. А если диспетчеризация тройная или выше? Тогда еще умножаем на количество слоев, и дальше и дальше…

Как бы упростить жизнь? А вот так - если взаимодействие двух объектов дает один результат, пусть этим и занимается одна функция. Попробуем перевести на человеческий язык:

Пусть есть класс CTitanic и класс CIceberg. Их карма в том, чтобы столкнуться. Четыре варианта взаимодействия: Столкновение двух Ctitanic не ведет ни к чему, если вообще возможно, двух CIceberg - у них там свои дела, столкновение CTitanic и CIceberg, как известно, к семи Оскарам, и столкновение CIceberg и CTitanic - к тому же самому. То есть функций всего три. Определим взаимодействие этих классов как функцию hit(). Вот код:

>#include ‹iostream.h›

>// Форвардные объявления

>class CTitanic;

>class CIceberg;

>class CFloating;


>// Абстрактный базовый класс

>class CFloating {

>public:

> virtual void hit(CIceberg&)=0;

> virtual void hit(CTitanic&)=0;

>public:

> virtual void hit(CFloating&)=0;

>};


>// Класс айсберга

>class CIceberg {

>public:

> virtual void hit(CIceberg&);

> virtual void hit(CTitanic&);

>public:

> virtual void hit(CFloating&);

>};


>// Первая диспетчерская функция

>void CIceberg::hit(CFloating& _co) {

> _co.hit(*this);

>}


>// Две реализации взаимодействия

>void CIceberg::hit(CIceberg& _ci) {

> cout ‹‹ "ci+ci" ‹‹ endl;

>}


>void CIceberg::hit(CTitanic& _ct) {

> cout ‹‹ "ci+co" ‹‹ endl;

>}


>// Класс Титаника

>class CTitanic {

>public:

> virtual void hit(CIceberg&);

> virtual void hit(CTitanic&);

>public:

> virtual void hit(CFloating&);

>};


>// Еще одна диспетчерская функция

>void CTitanic::hit(CFloating& _co) { _co.hit(*this); }


>// А вот эта функция могла бы быть реализацией

>// но мы ее тоже делаем диспетчерской;

>// в этом фрагменте диспетчеризация тройная.

>void CTitanic::hit(CIceberg& _ci) {

> // cout ‹‹ "co+ci" ‹‹ endl; Это могла быть реализация

> _ci.hit(*this);

>}


>void CTitanic::hit(CTitanic& _ct) {

> cout ‹‹ "co+co" ‹‹ endl;