Программирование >>  Инициализация объектов класса, структура 

1 ... 306 307 308 [ 309 ] 310 311 312 ... 395


class RiSpotLight : public SoSpotLight { ... } class RiPointLight : public SoPointLight { ... }

подтипы источников освещения:

class RiDirectionalLight : public SoDirectionalLight { ... }

Новые подтипы содержат дополнительную информацию, необходимую для рендеринга с помощью RenderMan. При этом базовые классы Open Inventor по-прежнему позволяют выполнять рендеринг с помощью OpenGL. Неприятности начинаются, когда возникает необходимость расширить поддержку теней.

В RenderMan направленный источник и прожектор поддерживают отбрасывание тени (поэтому mi называем их источниками освещения, дающими тень, - SCLS), а точечный -нет. Общий алгоритм требует, чтобы mi обошли все источники освещения на сцене и составили карту теней для каждого включенного SCLS. Проблема в том, что источники освещения хранятся в графе сцены как полиморфные объекты класса SoLight. Хотя mi можем инкапсулировать общие данные и необходимые операции в класс SCLS, непонятно, как включить его в существующую иерархию классов Open Inventor.

В поддереве с корнем SoLight в иерархии Open Inventor нет такого класса, из которого можно было бы произвести с помощью одиночного наследования класс SCLS так, чтобы в дальнейшем уже от него произвести SdRiSpotLight и SdRiDirectionalLight. Если не пользоваться множественным наследованием, лучшее, что можно сделать, - это сравнить член класса SCLS с кажд1м возможным типом SCLS-источника и вызвать

SoLight *plight = next scene light();

if ( RiDirectionalLight *pdilite =

dynamic cast<RiDirectionalLight*>( plight ))

else

pdilite->scls.cast shadow map();

RiSpotLight *pslite = dynamic cast<RiSpotLight*>( plight )) pslite->scls.cast shadow map();

соответствующую операцию:

и так далее

(Оператор dynamic cast - это часть механизма идентификации типов во время выполнения (RTTI). Он позволяет опросить тип объекта, адресованного полиморфным указателем или ссылкой. Подробно RTTI будет обсуждаться в главе 19.)

проектировался еще до появления пространств имен). Точечный источник (point light) -это источник света, излучающий, как солнце, во всех направлениях. Направленный источник (directional light) - источник света, излучающий в одном направлении. Прожектор (spotlight) - источник, испускающий узконаправленн1й конический пучок, как обычный театральный прожектор.

По умолчанию Open Inventor осуществляет рендеринг графа сцен: на экране с помощью библиотеки OpenGL (см. [NEIDER93]). Для интерактивного отображения этого достаточно, но почти все изображения, сгенерированные для киноиндустрии, сделаны с помощью средства RenderMan (см. [UPSTILL90]). Чтобы добавить поддержку такого алгоритма рендеринга мы, в частности, должны реализовать собственные специальные



Пользуясь множественным наследованием, мы можем инкапсулировать подтипы SCLS, защитив наш код от изменений при добавлении или удалении источника освещения (см. рис. 18.1).


oPointLfgM-PointLjight

class RiDirectionalLight :

public SoDirectionalLight, public SCLS {

class RiSpotLight :

public SoSpotLight, public SCLS {

...

SoLight *plight = next scene light(); if ( SCLS *pscls = dynamic cast<SCLS*>(plight))

Рис. 18.1. Множественное наследование источников освещения

pscls->cast shadow map();

Это решение несовершенно. Если бы у нас был доступ к исходным текстам Open Inventor, то можно было бы избежать множественного наследования, добавив к SoLight член-

class SoLight : public SoNode { public:

void cast shadow map()

{ if ( scls ) scls->cast shadow map(); }

...

protected:

SCLS * scls;

...

SdSoLight *plight = next scene light();

указатель на SCLS и поддержку операции cast shadow map() :

plight-> cast shadow map();



Самое распространенное приложение, где используется множественное (и виртуальное) наследование, - это потоковая библиотека ввода/вывода в стандартном C++. Два основных видимых пользователю класса этой библиотеки - istream (для ввода) и ostream (для вывода). В число их общих атрибутов входят:

информация о форматировании (представляется ли целое число в десятичной, восьмеричной или шестнадцатеричной системе счисления, число с плавающей точкой - в нотации с фиксированной точкой или в научной нотации и т.д.);

информация о состоянии (находится ли потоковый объект в нормальном или ошибочном состоянии и т. д.);

информация о параметрах локализации (отображается ли в начале даты день или месяц и т. д.);

буфер, где хранятся данные, которые нужно прочитать или записать.

Эти общие атрибуты вынесены в абстрактный базовый класс ios, для которого istream и ostream являются производными.

Класс iostream - наш второй пример множественного наследования. Он предоставляет поддержку для чтения и записи в один и тот же файл; его предками являются классы istream и ostream. К сожалению, по умолчанию он также унаследует два различных экземпляра базового класса ios, а нам это не нужно.

Виртуальное наследование решает проблему наследования нескольких экземпляров базового класса, когда нужен только один разделяемый экземпляр. Упрощенная иерархия iostream изображена на рис. 18:2:-

(fst re a

-tes-

idstream

fstream

Ofstream-

Рис. 18.2. Иерархия виртуального наследования iostream (упрощенная)

Еще один реальный пример виртуального и множественного наследования дают распределенные объектные вычисления. Подробное рассмотрение этой темы см. в серии статей Дугласа Шмидта (Douglas Schmidt) и Стива Виноски (Steve Vinoski) в [LIPPMAN96b].

В данной главе мы рассмотрим использование и поведение механизмов виртуального и множественного наследования. В другой нашей книге, Inside the C++ Object Model , описаны более сложные вопросы производительности и дизайна этого аспекта языка.

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



1 ... 306 307 308 [ 309 ] 310 311 312 ... 395

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика