Этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
Политика конфиденциальности
|
|
|
агрегация (и включение)
|
|||
|---|---|---|---|
|
#18+
встретил утверждение, о том что "в VB агрегация отсутствует". Почему я должен считать, что оно справедливо. ЗЫ Возможно, я не вполне понимаю, что такое агрегация. Могут потребоваться разъяснения. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.07.2004, 16:30 |
|
||
|
агрегация (и включение)
|
|||
|---|---|---|---|
|
#18+
В ожидании ответа решил изложить собственное понимание данного вопроса. Возможно это исчерпает тему, или повернет ее несколько в иное русло. Понимание получается малость многословным, поэтому разбиваю его на части в целях обеспечения «удобочитаемости». Информация для вероятных «просто читателей». Уточнение 1. – обсуждается VB6 (и ниже – 5, 4) Уточнение 2. Я не являюсь и не считаю себя «программером», хотя и способен куриным почерком царапать кусочно-грязный код на VB/VBA. При этом на настоящий момент времени справедливо утверждение о том, что НИКАКИМИ другими языками я не владею. По складам и с ошибками готов читать код Java и C++ . В ожидании ответа «перелистывал MSDN» и набрел на такую фразу: “This time I was thwarted by the complete lack of support for aggregation in Visual Basic.” (“House of COM” by Don Box, from the March 1999 issue of Microsoft Systems Journal ). Возможно, автор исходного утверждения восходит именно к этой статье. Однако прозвучала цитированная фраза во вполне определённом контексте, в отрыве от которого превращается попросту в неверную. А именно в контексте агрегирования интерфейсов COM. Причем под агрегированием понимается конкретная техника реализации множественности интерфейсов в одном классе с использованием вложенных классов (в первоисточнике - nested), по ряду признаков восходящая непосредственно к источникам в Microsoft Corp. Описание такой агрегации может быть найдено в статье MSDN, содержащей выдержки из The COM Programmer's Cookbook, Crispin Goswell Microsoft Office Product Unit Spring 1995 Revised: September 13, 1995. В таком контексте я соглашусь с утверждением о том, что VB не поддерживает агрегации. Однако в расшифрованном и дополненном виде она (фраза) будет звучать так: «VB (синтаксически) не поддерживает агрегации (интерфейсов COM)». Вообще говоря, даже шире – интерфейсов, как они понимаются в VB. Далее я хотел бы 1) описать сходства и различия в реализации COM интерфейсов в VB и С++ как я их понимаю и в контексте обсуждаемого вопроса; 2) специально для вероятного отвечающего осветить вопрос, почему в VB реализовать и наследовать – полные синонимы; 3) поставить вопрос о возможности обхода синтаксической не реализуемости агрегации интерфейсов; 2) Объяснить, почему я считаю, что VB поддерживает агрегацию как общую логическую концепцию. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.07.2004, 01:30 |
|
||
|
агрегация (и включение)
|
|||
|---|---|---|---|
|
#18+
Общее и отличия в реализации (наследовании) интерфейсов, или как VB не может реализовать агрегацию. Приношу извинения за «прописывание истин», которое вероятному отвечающему покажутся назойливыми, очевидными и излишними. Можно отнестись к этому просто как к зуду. Однако мне сейчас представляется нужным вставить этот «раздел». Кроме того, возможно, он окажется полезным начинающим VB/VBA-шникам, при всей его схематичности. Хотя в наше время, возможно, таких людей (начинающих) уже не осталось. (То есть все уже умные, - один я дураком остался). Спецификация COM подразумевает, что компонент обязан иметь некоторое количество входных интерфейсов и может (но не обязан) иметь некоторое количество выходных интерфейсов, посредством которых он (компонент) способен уведомлять внешний мир о своем внутреннем состоянии, связанным с использованием входных интерфейсов. Множество выходных интерфейсов интерпретируется внешним миром как СОБЫТИЯ входных интерфейсов. Однажды упомянув об этом, далее не будем возвращаться к этой теме, поскольку События не имеют непосредственного отношения к заявленной теме обсуждения в том смысле, что тема «агрегации» стандартно обсуждается по отношению к входным интерфейсам компонента. Только они (входные) интерфейсы будут подразумеваться в дальнейшем. Возможная схема реализации компонента COM в С++. Утв. 1) COM-компонент обязан объявить внешнему миру о доступных (входных) интерфейсах. Утв. 2) В C++ реализациях компонентов COM такие объявления «стандартно» производятся декларацией абстрактных классов. Использование абстрактных классов обусловлено тем, что его объявление задает «пустой» формат таблицы виртуальных функций (vTable), который и определяет входной интерфейс. Утв. 3) Один из вариантов «стандартной» реализации функционала компонента сводится к выписыванию единственного реализующего класса, наследующего все объявленные в компоненте интерфейсы (=абстрактные классы). Это, натурально, честное наследование, которое технически сводится к тому, что в vTable реализующего класса отводится пространство заранее известного ( в силу наличия объявления интерфейса как абстрактного класса) размера под размещение фактических адресов заявленных интерфейсом функций. Однако, поскольку наследование производится от абстрактного класса, размещать туда нечего и реализующий класс оказывается обязанным самостоятельно реализовать функции, заявленные интерфейсом и разместить в собственную vTable их фактические адреса. Весь этот процесс вполне синтаксически поддержан в C++. И чрезвычайно удобен в том отношении, что при таком подходе наиболее просто реализуется требование COM спецификации к реализации QueryInterface, заключающееся в том, что используя произвольный интерфейс компонента можно получить указатель на любой содержащийся в компоненте интерфейс. При вышеописанном подходе вырисовывается единственная функция QueryInterface, работа которой (по тексту) сводится к приведению указателя экземпляра реализующего класса к запрошенному клиентом интерфейсу. Технически такое приведение заключается в вычислении смещения куска, соответствующего vTable интерфейса в vTable реализующего класса и возврате адреса, соответстующего началу vTable интерфейса (в vTable реализующего класса). Именно по этой схеме и работает VB(6)/VBA. Располагая синтаксическим элементом Implements, он (VB) позволяет наследовать (=реализовывать) множество интерфейсов. При этом среда программирования следит за полнотой реализации заявленного интерфейса в реализующем классе, заставляя программиста выписывать реализующие функции как private- функции класса, адреса которых и размещаются в соответствующих (заявленных к реализации интерфейсом) местах vTable. На описанную выше схему далее будем ссылаться как на «стандартную». Пусть теперь в компоненте заявлено более одного интерфейса И, в целях разделения «кода по функционалу», мы хотим выписать поведение, реализующее функционал интерфейсов в различных внутренних (недоступных непосредственно клиентам) классах компонента, сохраняя схему с единственным реализующим непосредственно доступ к интерфейсам классом, как было описано выше. Такой заход приводит к схеме, общеупотребительно называемой делегированием. Существо которого заключается в том, что в качестве членов класса, реализующего компонент, заявляются экземпляры (внутренних) классов, реализующих поведение интерфейсов. При этом в функциях реализующего компонента происходит просто переадресация вызовов к функциям экземпляров соответствующих внутренних классов. Следует отметить что эта схема вполне очевидно работает в VB. Агрегацией интерфейсов (COM) Microsoft Corp. называет нечто совершенно специальное, а именно наличие в реализующем классе такого члена – экземпляра внутреннего класса, который 1) недоступен непосредственно клиенту иначе как через обращение к включающему его классу и, 2) такой экземпляр класса полностью реализует соответствующий ему COM-интерфейс и 3) В целом выполняется требование COM к QueryInterface, заключающееся в том, что через любой полученный интерфейс компонента может быть получен любой заявленный в компоненте интерфейс. 4) vTable класса- члена содержится в vTable включающего класса. Смысл вышеуказанного набора требований сводится к тому, что при запросе клиентом «агрегированного» интерфейса, агрегирующий класс имеет возможность отдать непосредственно указатель на включенный экземпляр, избегая выписывания реализующих функций в своем теле. В вышеприведенной «стандартной» схеме реализации множества интерфейсов это невозможно в принципе. Ослабим требование о непосредственной недоступности включенного класса. Будем просто не хотеть выписывать во включающем классе реализации всех функций заявленного интерфейса COM. Будем хотеть перенаправлять вызовы к внутреннему члену, самостоятельно реализовывающему необходимый COM- интерфейс. (Отказаться от наследования при этом в лет не получится, поскольку это создаст проблему правильного формирования vTable). Пусть нашелся способ, не отказываясь от наследования – еренаправлять «без делегирования». Тогда необходимо преодолеть еще одну проблему. Включенный экземпляр класса, как ожидается, полностью соответствует спецификации COM. Значит содержит собственную QueryInterface. Значит обязан, получив запрос на интерфейс включающего класса (а он у нас соответствует COM по изначальной постановке) уметь вернуть указатель на него ( его vTable ). Вышеприведенная комбинация (2х) проблем приводит как минимум к крайнему неудобству, а вообще говоря, к практической невозможности реализации «агрегации интерфейсов» в рамках «стандартной схемы». Поскольку VB следует именно «стандартной» схеме, в нем невозможна (по крайней мере, по синтаксису и соответствующей ему реализации) «агрегация интерфейсов COM». А поскольку VB всюду следует стандартной в вышеуказанном смысле “схеме COM” при работе со своими объектами, то утверждение расширяется до “В VB невозможно реализовать агрегацию интерфейсов” . В С++ агрегация интерфейсов COM реализуется посредством объявления ВЛОЖЕННОГО класса, ( в общем случае явно содержащего указатель на объемлющий класс; это позволяет решить проблему «универсальности QueryInterface» методом «внутреннего делегирования»), при котором обеспечивается «правильная структура vTаble» и появляется возможность «перенаправления без детального (для каждой функции) делегирования (=агрегации)». ЗЫ1 Хотел VB-like псевдокод нарисовать – но уж утро, а день предстоит тяжелый – пятница в конце месяца. Поневоле закругляюсь. Поскольку «плановый скелет», считаю что описал, продолжение по запросу. ЗЫ2 Именно следование «стандартной реализации» в VB делает работоспособной «схему изоморфных интерфейсов по Балене». Которая используется в двух ипостасях – а) как трюк, позволяющий переопределять фактические параметры, передаваемые методу класса в проекте VB, и б) ускорять обращения к внешним (ActiveX ) объектам, благодаря подмене vTable и соответствия смещений в подменяемых vTable методов внутренних по отношению к проекту VB «абстрактных классов» смещениям методов во внешних ActivX (контролах). ЗЫ3 На этой же особенности VB основана техника частичной подмены vTable динамически создаваемыми функциями. ЗЫ4 На последней из указанных техник потенциально может быть основана «реализация в VB» «агрегации интерфейсов», невзирая на ее теоретическую синтаксическую невозможность. Собственно это и можно было бы вынести как вопрос для дальнейшего обсуждения, при том, что я абсолютно не уверен, что эту дорогу можно пройти до конца. Более того, VB-правильно не вставать на нее вообще, поскольку это существенно «внеязыковая» техника. ЗЫ5 Все вышесказанное не имеет отношения к фразе «VB не поддерживает агрегацию». Поскольку, являясь всего лишь логической концепцией, агрегация в реализации, как правило, неотличима от ассоциации (тоже лишь логическая концепция). И то и другое технически реализуется включением соответствующих объектных переменных. Применительно к «агрегации объектов» как общей концепции, объявление публичной объектной переменной в классе очевидно реализует агрегацию/ассоциацию. Public agrObject as agrClass Инкапсулирующая конструкция, на мой взгляд, тоже не противоречит логике применения термина «агрегация» в большинстве своих практических использований. Кажется я выложился… Жду либо иной точки зрения от вероятного отвечающего, либо согласия. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.07.2004, 04:50 |
|
||
|
агрегация (и включение)
|
|||
|---|---|---|---|
|
#18+
вот проврался ( вроде трезвый был). в "изоморфных интерфейсах" речь идет о подмене формальных параметров, конечно. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.07.2004, 09:41 |
|
||
|
агрегация (и включение)
|
|||
|---|---|---|---|
|
#18+
Ща все будет. Только до инета дорвался. Пытаюсь прочитать все написанное :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.07.2004, 10:03 |
|
||
|
агрегация (и включение)
|
|||
|---|---|---|---|
|
#18+
прочитал. понял не все :) сначала неотносящиеся к делу замечания. Спецификация COM подразумевает, что компонент обязан иметь некоторое количество входных интерфейсов и может (но не обязан) иметь некоторое количество выходных интерфейсов, посредством которых он (компонент) способен уведомлять внешний мир о своем внутреннем состоянии, связанным с использованием входных интерфейсов. Множество выходных интерфейсов интерпретируется внешним миром как СОБЫТИЯ входных интерфейсов. Вообще говоря - неверно. Разделение интерфейсов на "входные" и "выходные" - это уже из области AcitveX, в "чистом" COM-е есть просто интерфейсы. Утв. 1) COM-компонент обязан объявить внешнему миру о доступных (входных) интерфейсах. Абсолютно неверно. COM-объект обязан предоставить внешнему миру корректную реализацию интерфейса IUnknown. И все. Реализация IUnkown есть необходимое и достаточное условие для того, чтобы объект считался COM-объектом. Предоставление списка доступных интерфейсов - это уже задача TypeLibrary, наличие tlb является необходимым только для COM+ объектов (вроде бы) Теперь по делу. Немного непонятно, почему делегирование появилось в обсуждении только в момент перехода к компонентам, реализующим несколько интерфейсов. В общем случае можно рассматривать делегирование, т.е. перенаправление вызовов интерфейсных функций, и в случае всего одного интерфейса. Хотя, справедливости ради, надо отметить, что отличие между двумя реализациями агрегации (т.е. между "ручным делегированием" и предложенный тобою "приватный объект + property get") во всей красе проявляются именно в случае многоинтерфейсных компонентов: При использовании "ручного делегирования" мы имеем компонент, реализующий несколько интерфейсов, причем сохраняются все требования COM. Т.е. имея ссылку на один интерфейс мы можем добраться до любого, поддерживаемого "внешним" объектом, при этом не можем получить доступ к другим (побочным) интерфейсам "агрегированного" объекта. Как внешний компонент использует внутренний - исключительно его дело. При использовании "приватного объекта + property get" - имея ссылку на внутренний компонент мы не можем получить ссылки на интерфейсы внешнего, зато получаем ссылки на другие интерфейсы внутреннего (хоть они и не нужны/не желательны) Так что, ослабляя требование о непосредственной недоступности внутреннего класса - мы имеем нарушение одного из основных требований COM, а именно что если интерфейс доступен через ссылку хотя бы на один интерфейс - то он доступен через ссылку на любой. В С++ агрегация интерфейсов COM реализуется посредством объявления ВЛОЖЕННОГО класса Если под "вложенным" классом подразумевается следующее: Код: plaintext 1. 2. 3. 4. 5. 6. 7. ЗЫ2 Именно следование «стандартной реализации» в VB делает работоспособной «схему изоморфных интерфейсов по Балене». Эээ... Вы такой умный... Вам череп не жмет? Что такое "«схема изоморфных интерфейсов по Балене" - моя не понимает. Насчет "синтаксической" возможности/невозможности. Что вообще обозначает "синтаксически" поддерживает/не поддерживает? COM-объект - это некий объект, который имеет жестко-фиксированную структуру VTable. По "счастливой случайности" эта структура совпадает со структурой vTable, которую генерят все С++ компиляторы при множественном наследовании от чисто абстрактных классов. Только за счет этого, видимо, можно говорить о "синтаксической поддержке". Однако агрегированние - это вопрос, выходящий за рамки интерфейсов как чисто абстрактных классов, и уже касающийся конкретной реализации нужных интерфесов. Т.е., повторюсь, реализация (имплементация, наследование) - интерфейсов , а вот агрегация - объектов Программируя на C++ мы имеем доступ к реализации IUnkown (т.е. собственно мы сами ее и делаем), и можем сделать корректную реализацию оного и в агрегируемом, и в агрегирующем классе. Программируя на VB - доступа к реализации IUnkown мы не имеем. Сами сделать "агрегатную" реализацию IUnkown мы не можем. Язык - не предоставляет синтаксических конструкций, которые компилировались бы в нужную ("агрегатную") реализацию. Стало быть - не поддерживается агрегация в VB, в том числе и синтаксически. Остается лишь агрегацию вручную, т.е. делегирование всех методов. Это все равно что пытаться написать custom-marshalling на VB. Невозможно в принципе, ибо кастом-маршаллинг есть реализация интерфейсов, скрытая от нас самим языком. Или, к примеру, попытаться средствами VB сделать один обработчик ActiveX-событий, который будет обрабатывать события от несколький однотипных объектов. Это есть тоже реализация интерфейсов (каких-то там IConnectionPoint, IConnectionPointContainer и т.п.), эта реализация доступна при программировании на C++, и недоступна при программировании на VB Применительно к «агрегации объектов» как общей концепции, объявление публичной объектной переменной в классе очевидно реализует агрегацию/ассоциацию. Public agrObject as agrClass Ну нет же. Вместо объекта, реализующего интерфейс IA, IB, IC - ты предоставляешь объект, реализующий интерфейсы IA, IB + какой-то отросток (public property get), возвращающий что-то вообще непонятное (но с интерфейсом IC). Если такая подмена (вместо IA, IB, IC - IA, IB и фунт прованского масла) некритична - то можно считать это заменой агрегирования. Иначе только ручное делегирование всех методов конкретного интерфейса. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.07.2004, 15:05 |
|
||
|
агрегация (и включение)
|
|||
|---|---|---|---|
|
#18+
детально отвечу позже, если у тебя есть желание "слушать" (в том числе про изоморфные интерфейсы). А пока, коротко, я не вполне понял, до чего же мы договорились по поводу VB? Твое исходное утверждение - VB не поддерживает агрегацию. Моя поправка - как абсолютное это утверждение неверно. Верно следующее - в VB нет встроенных механизмов поддержки агрегации интерфейсов. Если ты с этим уточнением согласен - тему можно закрыть. Более того. Готов в дальнейшем не реагировать на утверждения следующего содержания отвечающий яПрименительно к «агрегации объектов» как общей концепции, объявление публичной объектной переменной в классе очевидно реализует агрегацию/ассоциацию. Public agrObject as agrClass Ну нет же. Вместо объекта, реализующего интерфейс IA, IB, IC - ты предоставляешь объект, реализующий интерфейсы IA, IB + какой-то отросток (public property get), возвращающий что-то вообще непонятное (но с интерфейсом IC). Если такая подмена (вместо IA, IB, IC - IA, IB и фунт прованского масла) некритична - то можно считать это заменой агрегирования. Иначе только ручное делегирование всех методов конкретного интерфейса. как далее неинтересные в контексте проведенного обсуждения. ЗЫ есть пара минут. Поэтому одно замечание все-таки размещу. Утверждение о возможности реализации агрегации интерфейсов в изложенном выше смысле без использования вложенных класов представляется мне НЕВЕРНЫМ по следующим основаниям. в этой теме 2 момента - QueryInterface И сруктура vTable. Вопрос с QueryInterface в общем случае решется через включение/делегирование. Однако не обязательно при этом в любом проекте сохраняется "прозрачное управление кодом". Интереснее вопрос с vTable. 1) если (уникальный "главный" класс, через который осуществляется доступ к "агрегированному" классу-реализатору интерфейса ) наследует тот же интерфейс в целях обеспечения "правильной vTable", то он НЕ МОЖЕТ УЙТИ ОТ ДЕЛЕГИРОВАНИЯ, а это "не то". 2) Если он НЕ наследует "тот" интерфейс, а просто включает экземпляр класса- реализатора, то он имеет НЕПРАВИЛЬНЫЙ vTable. В его vTable в таком случае НЕ РАЗМЕЩАЕТСЯ соответсвующий интерфейсу vTable. А размещается указатель на приватный член-экземпляр-реализатор. Подходящую QueryInterface в этом случае написать нельзя, поскольку ей нечего возвращать - в vTable объемлющего класса просто нет нужного раздела. А по постановке наружу должен смотреть только он и полученные клиентом адреса функций ДОЛЖНЫ находиться в vTable агрегирующего класса. По счастью, механизм вложения классов ОБЕСПЕЧИВАЕТ правильность vTable для агрегирующего класса. Еще раз, мы НЕ обсуждаем вариант реализации COM интерфейсов множеством независимых классов-реализаторов. Мы обсуждаем агрегацию интерфейсов, как она описана Microsoft применительно к COM. Я действительно, не владею предметом, в обсуждение которого "влез". Возможно это извиняет мое непонимание того, как можно реализовать обсуждавшуюся "агрегацию COM интерфейсов" без использования вложенных классов. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.07.2004, 16:35 |
|
||
|
агрегация (и включение)
|
|||
|---|---|---|---|
|
#18+
вот еще пару мин. откопал. про "изоморфные интерфейсы по Балене" вот пара ссылок, на самом деле, должна бы быть еще по крайней мере одна. Но щас лень искать http://www.ftponline.com/archives/premier/mgznarch/vbpj/2000/09sep00/bb0009/bb0009.asp http://www.ftponline.com/archives/premier/mgznarch/vbpj/2000/08aug00/bb0008/bb0008.asp в двух словах. Пусть есть класс А и класс Б. Балена зовет их изоморфными, если они имеют одинаковый формат vTable (размер таблицы и последовательность расположения функций в них), сами функции должны иметь по крайней мере одинаковую глубину стека параметров, и быть одноименными. Тогда при подмене указателя на vTable класса А указателем на vTable класса Б, код, использующий класс А сохраняет свою работоспособность. Пусть есть Dim obj1 As КлассА Dim obj2 As КлассБ Пусть Set obj1 = New КлассА Dim vaR var = obj1.Func1 Далее, пусть производится копирование указателя на vTable одного класса в другой CopyMemory objPTR(obj1) ,objPTR(obj2), 4 тогда var = obj1.Func1 продолжает работать, но исполняет его уже фактически другой объект. Применительно к "внутреннему" для проекта VB использованию этот трюк позволяет реализовать подобие адресной арифметики и имитировать прямое обращение к памяти. Применительно к работе с внешними (ActiveX) объектами - позволяет, выражаясь неформально, "усилить раннее связывание". За разъснениями по ссылкам. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.07.2004, 20:09 |
|
||
|
|

start [/forum/topic.php?fid=16&gotonew=1&tid=1348306]: |
0ms |
get settings: |
9ms |
get forum list: |
14ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
179ms |
get topic data: |
10ms |
get first new msg: |
6ms |
get forum data: |
2ms |
get page messages: |
51ms |
get tp. blocked users: |
1ms |
| others: | 14ms |
| total: | 292ms |

| 0 / 0 |
