|
Программирование >> Инициализация объектов класса, структура
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 , описаны более сложные вопросы производительности и дизайна этого аспекта языка. Для последующего обсуждения мы выбрали иерархию животных в зоопарке. Наши животные существуют на разных уровнях абстракции. Есть, конечно, особи, имеющие
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |