![]() |
Модераторы: Partizan, gambit |
![]() ![]() ![]() |
|
Vit |
|
|||
![]() Vitaly Nevzorov ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 10964 Регистрация: 25.3.2002 Где: Chicago Репутация: 1 Всего: 207 |
Создал я 3 класса и работать это не хочет... Вопервых непонятно почему, во вторых - а как быть?
Ошибка: cannot convert from 'Param' to 'StrParam' ![]() ![]() Это сообщение отредактировал(а) Vit - 4.5.2007, 00:42 -------------------- With the best wishes, Vit I have done so much with so little for so long that I am now qualified to do anything with nothing Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru |
|||
|
||||
stab |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 1839 Регистрация: 1.1.2003 Репутация: 22 Всего: 48 |
до настолько динамической перегрузки языки ещё не дошли. ты пытаешся сделать, чтобы во время выполнения исходя из типа параметра вызывался соответсвующий перегруженный метод. не бывает так.
как вариант: можно определить ReadParam виртуальным в классе Param, и во всех потомках дать ему свой функционал (перекрыть). тогда цикл чтения будет выглядеть примерно так:
полиморфизм короче. при таком варианте считанные данные лучше всего хранить в самом экземпляре потомка Param. .. или ещё как-то передизайнить код ![]() -------------------- 6, 6, 6 - the number of the beast. |
|||
|
||||
Hurricane |
|
||||||||
Шустрый ![]() Профиль Группа: Участник Сообщений: 126 Регистрация: 10.4.2007 Репутация: 3 Всего: 9 |
Точнее даже не из типа параметра, а из типа возвращаемого значения. Vit, в принципе, можно извернуться и сделать, как ты хочешь, но это сводит на нет всю идею объектно-ориентированного программирования:
т.е. ты сам выясняешь, какого типа на самом деле текущий элемент списка, и вызываешь соответствующий метод. Лучше, наверно, что-то типа вот так:
Но лучше всего сделать, как написал cully, только придется передизайнить. Проблема будет в том, что ты хочешь получать возвращаемые значения из метода ReadParam(), но они, по идее, разные (int и String). Можно возвращать object, но это проблемы не решает - под ним может скрываться int или string. А надо ли их различать? Допустим, нам надо вывести это значение в поток. Вот и передадим ему поток, пусть он сам себя и выводит:
Это сообщение отредактировал(а) Hurricane - 4.5.2007, 07:13 |
||||||||
|
|||||||||
adLucem |
|
||||||||
Шустрый ![]() Профиль Группа: Участник Сообщений: 94 Регистрация: 17.4.2007 Где: Украина, Донецк Репутация: 4 Всего: 5 |
Полиморфизм обеспечивает приведение от потомка к предку, но не от предка к потомку (потому что, в общем случае, неизвестно к какому потомку приводить). Теория Допустим имеем следующую иерархию:
В вашем случае иерархия более проста, но компилятор также не будет пытаться разрешить тип потомка относительно предка. Любое приведение от типа предка к типу потомка считается неоднозначным в статических языках. Практика Анализ ошибки
Исправленный код (внесены некоторые изменения в код Hurricane) Сохранение результатов динамического приведения во временной переменной - рекомендация Microsoft (см. FxCop 1.35).
Исправленный код (вариант 2) Более красивый вариант с точки зрения кода (имхо), но с дополнительными затратами на повторяющееся динамическое приведение типов.
Возможно вынесение полиморфного поведения в наследники (см. пост Hurricane), но это не всегда допустимо. Если программа требует динамического определения типа то возможно нужно провести рефакторинг и перенести полиморфное поведение в классы наследники (см. предыдущие посты). Это сообщение отредактировал(а) adLucem - 4.5.2007, 10:34 |
||||||||
|
|||||||||
tol05 |
|
||||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1632 Регистрация: 21.12.2006 Где: Харьков Репутация: 63 Всего: 170 |
Извините что вмешался, но почитав пост adLucem
вынужден сказать, что я понимаю полиморфизм по-другому ![]() Класс потомка всегда нужно передавать в качестве класса предка. И вызывать нужно всегда методы предка. Только они, конечно должны быть переопределены overrided в потомках. НИКОГДА НЕ НУЖНО ПРОВЕРЯТЬ ТИП - ЭТО ЗАБИВАНИЕ ГВОЗДЕЙ МИКРОСКОПОМ. Еще Reflection для анализа типов использовать можно! Нафиг тогда полиморфизм? Виртуальные функции? Перекрой методы в потомке и именно они для каждого потомка и будут вызываться. В таблице методов потомка будут прописаны ИХ адреса. Отличие виртуальных методов от невиртуальных в том, что адреса виртуальных методов в таблице методов предка переписываются на адреса потомков. Обращение к методу класса для невиртаульных функций - на адрес в таблице класса, под которым объявлена ссылка, для виртуальных - на адрес в таблице класса, под которым создан объект! Когда ссылка класса предка ссылается на объект класса потомка и происходит вызов функции, то идет обращение к указателю на таблицу методов объекта (он реально - потомок). При создании потомка он получил (когда класс загружался в память) таблицу методов предка и переписал в ней адреса виртуальных ф-ций на адреса своих , ну и еще свои, новые написал. Компилятор только проверяет, чтобы обращения к методам были в объеме родительской таблицы (объеме класса ссылки, которая СЕЙЧАС на этот объект в куче ссылается) и все. А в run-time объект, под какой бы он ссылкой ни находился, хоть под object, сам хранит в себе истинную таблицу (ее доступность только усекается время от времени или восстанавливается). Одним словом сделай в базовом классе
в потомках
и везде вызывай одинаково
Да, кстати, когда в методе анализируется тип переданного параметра, то тоже происходит проверка допустимости его использования в качестве типа, указанного при объявлении метода. И приведение будет неявным. Извините за многословность и не академическое изложение. Это сообщение отредактировал(а) tol05 - 4.5.2007, 10:11 -------------------- На хорошей работе и сны хорошие снятся. |
||||||||
|
|||||||||
adLucem |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 94 Регистрация: 17.4.2007 Где: Украина, Донецк Репутация: 4 Всего: 5 |
![]() ![]() С теоретической точки зрения это конечно же звучит прекрасно, но с практической динамическое приведение типов - это полноценный ООП инструмент, который используется также как и другие инструменты и для применения которого есть достаточно серьезные основания. Кроме того не следует дублировать решения (имхо), которые уже освещены (см. пост Hurricane).
Если вы решили теоретизировать - то ссылайтесь на источники. И если уж пишите теорию (которую кстати написали до вас и весьма неплохо), то зачем вы все таки приводите код? Извиняюсь за ![]() |
|||
|
||||
tol05 |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1632 Регистрация: 21.12.2006 Где: Харьков Репутация: 63 Всего: 170 |
За тон извиняюсь.
По поводу
оснований не вижу. Методов, добавленных в потомки и требующие вызовов через ссылку базового класса не вижу, а ВЫ? З.Ы. Право ссылаться на источники я с удовольствием предоставляю Вам. ![]() Это сообщение отредактировал(а) tol05 - 4.5.2007, 10:36 -------------------- На хорошей работе и сны хорошие снятся. |
|||
|
||||
adLucem |
|
||||
Шустрый ![]() Профиль Группа: Участник Сообщений: 94 Регистрация: 17.4.2007 Где: Украина, Донецк Репутация: 4 Всего: 5 |
Наследование применяется с двумя целями расширение и специализация [Мейер Б. "Конструирование объектно-ориентированных систем"]. В случае специализации методы, описанные в базовом классе, перегружаются в методах классов наследников и, следовательно, могут обрабатываться универсальными алгоритмами (это тот полиморфизм о котором вы говорите). В случае расширения классы наследники могут предоставлять дополнительные сервисы, которых нет у базового класса. В таком случае клиентский код, для вызова дополнительных сервисов, должен осуществлять динамическое приведение типов. Специализация и расширение часто комбинируются, что зачастую связано с тем, что разработчики расширений не имеют доступ к исходному коду базовых библиотек (в которых описаны расширяемые классы). Это усложняет логику клиента, требуя ввода дополнительных конструкций ветвления и в последующем может устраняться с применением рефакторинга (если дополнительные сервисы можно перенести в базовый класс и имеется доступ к базовому классу, в частности [Кериевски "Рефакторинг с применением шаблонов"]). Мысль о необходимости перенесения логики ветвления в полиморфную логику должна рассматриваться в рамках каждой отдельной задачи и однозначно выделить общее предпочтительное нельзя (особенно с учетом того, что полиморфная логика заведомо сложнее логики ветвления). Пример (кстати пример не такой уж надуманный и если вы все еще не согласны, то могу дать описание реальной архитектуры, где несмотря на использование ссылки на базовый класс необходимо применение динамического приведения типа).
Это сообщение отредактировал(а) adLucem - 4.5.2007, 10:51 |
||||
|
|||||
adLucem |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 94 Регистрация: 17.4.2007 Где: Украина, Донецк Репутация: 4 Всего: 5 |
Пример архитектуры с применением динамического приведения типов.
В данной архитектуре (основана на модели доменной области) классам SqlReceiver требуется специализированный объект сессии SqlSession, но он должен принимать указатель на более общий класс (в данном случае интерфейс), потому что все получатели создается универсальной динамической фабрикой, которая создает получатели для разных видов сессий, которые определяются после запуска приложения. То есть сам по себе получатель использует только специализацию, но требует расширения от сессии.
Это сообщение отредактировал(а) adLucem - 4.5.2007, 11:10 |
|||
|
||||
Hurricane |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 126 Регистрация: 10.4.2007 Репутация: 3 Всего: 9 |
Э, вот тут ты не прав. adLucem уже привел пару примеров, я добавлю еще от себя - на практике, особенно в больших проектах, довольно часто возникает ситуация, что нельзя модернизировать базовый класс (к тому же он может быть не один), а начиная с какого-то уровня иерархии надо добавить какие-то функциональные возможности. Вносить все в базовый класс не имеет смысла, он про эти новые функции ничего не знает. И не всегда возможно, по разным причинам - это может потребовать огромного количества изменений, этот класс может использоваться в нескольких проектах и внесение изменений в него нежелательно, и др. Хорошо, если удается сделать "промежуточный" базовый класс - унаследовать его от старой иерархии, добавить абстрактные методы, и от этого класса уже делать специализированные классы, а хранить-передавать по ссылке на этот "промежуточный" класс, но это усложнение не всегда оправдано (например, требуется всего один специализированный класс), а главное - мы все равно уже не гарантированы от ненужности проверки типов. Безусловно - код выглядит красивее. Но если в данном случае это реализовано также, как сиплюсплюсное dynamic_cast<> (или IsKindOf( RUNTIME_CLASS( )) ) - накладные расходы на этот вызов очень большие, поэтому стоит пожертвовать красотой в пользу оптимальности и скорости. |
|||
|
||||
tol05 |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1632 Регистрация: 21.12.2006 Где: Харьков Репутация: 63 Всего: 170 |
Ничего не понял, Hurricane
Какая связь между сложностями модернизации больших проектов и необходимостью проверять типы? Что ты имеешь в виду? ![]() Это сообщение отредактировал(а) tol05 - 4.5.2007, 17:06 -------------------- На хорошей работе и сны хорошие снятся. |
|||
|
||||
Vit |
|
|||
![]() Vitaly Nevzorov ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 10964 Регистрация: 25.3.2002 Где: Chicago Репутация: 1 Всего: 207 |
Пошли теоретические изыски. В принципе, ответ был дан culli во втором посте, и как для меня - то ответ исчерпывающий. Огромное спасибо!
-------------------- With the best wishes, Vit I have done so much with so little for so long that I am now qualified to do anything with nothing Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru |
|||
|
||||
stab |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 1839 Регистрация: 1.1.2003 Репутация: 22 Всего: 48 |
Vit, всегда пожалуйста.
-------------------- 6, 6, 6 - the number of the beast. |
|||
|
||||
mr.DUDA |
|
|||
![]() 3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 110 Всего: 232 |
adLucem,
tol05, Полиморфизм - удобный инструмент для разработчика сложных систем (как и рефлексия). Применения и того и другого в каждом конкретном случае требует от грамотного разработчика анализа - хотя бы минимального - тех pros and cos (преимуществ и недостатков), которые получаются в конкретном случае. Это главное что нужно держать в голове, остальное - детали. -------------------- ![]() |
|||
|
||||
![]() ![]() ![]() |
Прежде чем создать тему, посмотрите сюда: | |
|
Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов. Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :) Так же не забывайте отмечать свой вопрос решенным, если он таковым является :) Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |