С++ - язык, который изучается постепенно.Двойная передача
создание сайта визитки
Студия Web-дизайна, создание, раскрутка сайтов интернет реклама, подача объявлений на доски, продвижение и сопровождение сайтов
Карта сайта | Зарабатывайте с нами  | Сделать заказ
Наши услуги
Справочники
Самоучитель Internet Explorer
PHP и MySQL
Компьютерные сети
Самоучитель о С++
Новости
Новости для PDA
Реклама
Студия WebKuban.Ru - Создание и поддержка сайтов, интернет магазинов Каталог сайтов Всего.RU Интернет-каталог WWW.SABRINA.RU Refo.ru - русские сайты Каталог HeadNet.Ru Интернет-магазин цифровых товаров Каталог Ресурсов Интернет
Реклама
Язык С++
По последним данным, на рынке продается по крайней мере 2 768 942 книги о С++, не говоря уже о всевозможных курсах, обучающих программах, журналах и семинарах с коктейлями.
И все же в этом изобилии наблюдается удручающее однообразие.
Добро пожаловать на сайт студии Web-дизайна "САР"


Материалы книги получены с http://www.itlibitum.ru/

Двойная передача

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

Конечно, возможны силовые решения - например, запрятать в каждом экземпляре сведения о его типе. Однако более элегантное решение (и обычно более эффективное) решение носит название двойной передачи (double dispatch).

class Number {

protected:

// Диспетчерские функции для оператора +

virtual Number& operator+(const Integer&) = 0;

virtual Number& operator+(const Complet&) = 0;

// И т.д. для всех производных типов

public:

virtual Number& operator+(const Number&) = 0;

virtual Number& operator-(const Number&) = 0;

// И т.д.

};

class Integer : public Number {

private:

int I;

protected:

virtual Number& operator+(const Integer&);

virtual Number& operator+(const Complex&);

public

Integer(int x) : i(x) {}

virtual Number& operator+(const Number&);

// И т.д.

};

Number& Integer::operator+(const Number& n)

{

return n + *this; // Поменять местами левый и правый операнд

}

Number& Integer::operator+(const Integer& n)

{

// Ниже приведен псевдокод

if (i + n.i слишком велико для int) {

return ЦелоеСПовышеннойТочностью

}

else return Integer(i + n.i);

}

С этим фрагментом связана одна нетривиальная проблема, к которой мы вернемся позже, а пока сосредоточьте все внимание на концепции. Она похожа на стереограмму - чтобы скрытая картинка проявилась, вам придется расслабить глаза и некоторое время рассматривать код. Когда клиент пытается сложить два Integer, компилятор передает вызов Integer::operator+(), поскольку operator+(Number&) является виртуальным - компилятор правильно находит реализацию производного класса. К моменту выполнения Integer::operator+(Number&) настоящий тип левого операнда уже известен, однако правый операнд все еще остается загадкой. Но в этот момент наступает второй этап двойной передачи: return n + *this. Левый и правый операнды меняются местами, а компилятор приступает к поискам v-таблицы n. Однако на этот раз он ищет переопределение Number::operator+(Integer&), так как он знает, что *this в действительности имеет тип Integer.

Это приводит к вызову Integer::operator+(Integer&), поскольку типы обоих операндов известны и можно наконец произвести вычисления. Если вы так и не поняли, что же происходит, прогуляйтесь на свежем воздухе и попробуйте снова, пока не поймете. Возможно, вам поможет следующая формулировка: вместо кодирования типа в целой переменной мы определили настоящий тип Number с помощью v-таблицы.

Такое решение не только элегантно. Вероятно, оно еще и более эффективно, чем те, которые приходили вам в голову. Скажем, приходилось ли вам видеть код, генерируемый компилятором для конструкции switch/case? Он некрасив и вдобавок куда менее эффективен, чем последовательное индексирование двух v-таблиц.

Несмотря на всю элегантность, двойная передача довольно дорого обходится по объему кода и сложности:

1.   Если у вас имеется m производных классов и n операторов, то каждый производный класс должен содержать m*(n+1) виртуальных функций, да еще столько же чисто виртуальных заглушек в классе-предке. Итого мы получаем (m+1)*m*(n+1) диспетчерских функций. Для всех иерархий, кроме самых тривиальных, это довольно много.

2.   Если оператор не является коммутируемым (то есть ему нельзя передать повторный вызов с аргументами, переставленными в обратном порядке), это число удваивается, поскольку вам придется реализовать отдельные функции для двух вариантов порядка аргументов. Например, y/x - совсем не то же, что x/y; вам понадобится оператор / и специальная функция DivideInto для переставленных аргументов.

3.   Клиенты базового класса видят все устрашающие защищенные функции, хотя это им совершенно не нужно.

Тем не менее, в простых ситуациях двойная передача оказывается вполне разумным решением - ведь проблема, как ни крути, достаточно сложна. Специфика ситуации неизбежно требует множества мелких фрагментов кода. Двойная передача всего лишь заменяет большие, уродливые, немодульные конструкции switch/case более быстрой и модульной виртуальной диспетчеризацией.

Как правило, количество функций удается сократить, но при этом приходится в той или иной степени идти на компромисс с нашим строгим правилом - никогда не спрашивать у объекта, каков его настоящий тип. Некоторые из этих приемов рассматриваются ниже. Видимость производных классов для клиентов Number тоже удается ликвидировать минимальной ценой; об этом будет рассказано в главе 12. Как и во многих проблемах дизайна в С++, в которых задействованы матрицы операций, вам придется на уровне здравого смысла решить, стоит ли повышать модульность за счет быстродействия

или объема кода.


Назад    Содержание    Далее    



Специальное предложение


Сайт визитка за 90 $
создание, разработка сайта
  • Регистрация доменного имени в зоне .net.ru или .pp.ru (1 год)
  • Хостинг (1 год)
  • Готовый дизайн
  • Поддержка РНР
  • 3 страницы сайта (главная, о фирме, контакты)
  • Регистрация в 256 поисковых системах и каталогах
  • Форма сообщений
заказать создание сайта визитки
Размещение объявлений
Недорого предлагаем разослать ваше рекламное предложение о товарах или услугах на сотни досок объявлений по всему Рунету.
размещение объявлений на электронных досках
Друзья сайта
  • Реклама - каталог ресурсов Реклама - каталог ресурсов - Реклама Карта сайта
  • Просто добавь свой сайт
  • Ипотека, коммерческая и загородная недвижимость, продажа квартир и коттеджей
  • Выставки, выставки России, Выставки Москвы, зарубежные выставки
  • Music singer R&B song
  • Язык С++
    Просматривать полку книг о С++ в книжном магазине ничуть не интереснее, чем литературу по бухгалтерии. В сущности, все книги пересказывают одно и то же и отличаются разве что по весу и количеству цветов в диаграммах и таблицах.
    Copyright студия Web-дизайна САР © 2007
    Используются технологии uCoz