![]() |
|
Модераторы: Poseidon, Snowy, bems, MetalFan |
![]()
|
|
| Koster |
|
||||||
|
Новичок Профиль Группа: Участник Сообщений: 6 Регистрация: 2.6.2008 Репутация: нет Всего: нет |
В общем тема сложная для обьяснения. У меня есть два класса:
задача состоит в том как надо извратиться чтобы можна было выполнить данный код:
В классе TFloat не должно быть описания метода find полностью, т.е. основа (сам поисковый цыкл) должен остаться в классе TBase, чтобы можна было создавать другие типы на основе TBase и использовать его метод find. Я реализовал это таким образом:
В общем это работает, НО тут используется тип variant, который не может хранить указатель, да к тому же усложняет поиск ошибок связанных с несовместимостью типов. Мне хотелось бы узнать как это можна написать без вариантов? Это сообщение отредактировал(а) Alexeis - 3.6.2008, 09:24 |
||||||
|
|||||||
| Felan |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 284 Регистрация: 2.8.2007 Где: Самара Репутация: 2 Всего: 7 |
Сделай перегрузку в базовом классе... а вообще-то, фигню ты придумал. Может оп другому как-то это на классы разбить?
ЗЫЖ Public, Published и Protected члены и так доступны в наследниках. Так что для их вызыва из потомка вообще ничего делать не надо. -------------------- // Любая сложная система - это темный лес. Каждый в этом лесу протаптывает свои тропинки, по ним и бегает. Лишь изредка, сходя с них, мы находим много интересного, а порою и страшного. |
|||
|
||||
| ama_kid |
|
|||
![]() АСУТП-кодер ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1460 Регистрация: 5.3.2007 Где: Москва Репутация: 15 Всего: 95 |
Если я правильно понял вопрос, то я присоединяюсь к совету Felan. Что мешает использовать перегруженные (overload) функции? Создай свою функцию на каждый необходимый тебе тип в классе TBase:
-------------------- самурай без меча подобен самураю с мечом, но только без меча |
|||
|
||||
| pseud |
|
|||
![]() Экспёрт Тыдыщ ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1175 Регистрация: 18.5.2007 Где: Минск, Беларусь Репутация: 10 Всего: 40 |
а что мешает в базовом классе оперировать с double
ведь в переменную double не составит труда передать Integer а при необходимости доделки метода - переопределять его в потомке и дописывать юзая метод предка через inherited
Это сообщение отредактировал(а) pseud - 3.6.2008, 09:30 -------------------- Испытание чужого терпения можно считать успешным, если оно лопнуло... |
|||
|
||||
| Koster |
|
||||
|
Новичок Профиль Группа: Участник Сообщений: 6 Регистрация: 2.6.2008 Репутация: нет Всего: нет |
Начну по порядку.
Мешает то что заранее неизвестно какого типа будет передаваться элемент. Задача состоит в том чтобы можна было добавлять новые классы с новыми типами не меняя базовый. А типы могут быть любыми, вплоть до других классов. Перебрать их всех невозможно.
Думаю с предыдущих строк уже понятно, что типы которые передаются в метод find могут быть не только чисельные, а и сложные. Например string. Мое решение имеет недостаток в том что variant не может хранить указатели, а значит и сложные структуры данных типа классов. Поэтому хочется узнать как избавиться от variant'ов, если это конечно возможно на Delphi (на что я искренне надеюсь). А если невозможно, тогда может кто то скажет есть ли язык в котором это возможно. Это сообщение отредактировал(а) Koster - 3.6.2008, 16:55 |
||||
|
|||||
| pseud |
|
||||
![]() Экспёрт Тыдыщ ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1175 Регистрация: 18.5.2007 Где: Минск, Беларусь Репутация: 10 Всего: 40 |
тогда так
Добавлено через 4 минуты и 21 секунду ======================== или даже так
Добавлено через 6 минут и 38 секунд ========================= хотя, признаюсь, смысловой нагрузки в мною написанном наблюдаю слабо -------------------- Испытание чужого терпения можно считать успешным, если оно лопнуло... |
||||
|
|||||
| pseud |
|
|||
![]() Экспёрт Тыдыщ ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1175 Регистрация: 18.5.2007 Где: Минск, Беларусь Репутация: 10 Всего: 40 |
====================
а, вообще, - поддерживаю ama_kid. overload тебе в руки. главное объяви эти методы в базовом классе. а реализацию пиши в каждом отдельном потомке на свой метод. пример.
-------------------- Испытание чужого терпения можно считать успешным, если оно лопнуло... |
|||
|
||||
| Koster |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 6 Регистрация: 2.6.2008 Репутация: нет Всего: нет |
overload я понимаю как тут использовать. Это не проблема. Хотелось узнать как можно глубже Delphi.
Просто, а если исходника класса TBase нет под рукой, тогда как быть? А можете обьяснить по подробнее про reintroduce. Я не совсем понимаю смысл ее. Это сообщение отредактировал(а) Koster - 3.6.2008, 19:17 |
|||
|
||||
| Rohoss |
|
|||
![]() Начальник интернета ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1308 Регистрация: 9.10.2006 Где: Matrix Репутация: 4 Всего: 18 |
Типо замещает методы описанные в классе родителе и позволяет менять тип… Что-то вроде overload и override вместе взятых…
|
|||
|
||||
| Felan |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 284 Регистрация: 2.8.2007 Где: Самара Репутация: 2 Всего: 7 |
Да элементарно. Только для этого надо, как я тебе уже говорил, переделать структуру классов. Если у тебя всегда на этапе компиляции будут известны типы, которыми ты хочешь оперировать в базовом классе, то можно использовать виртуальные конструкторы для динамического создания объекта нужного класса. Или же можно сделать отдельный класс-менеджер, который выполняет нужные тебе функции с объектами и будет принимать определенный интерфейс (или базовый класс, но тогда надо будет делать наследников, а это не так эффективно) для того, что бы обрабатывать эти объекты. А все твои классы, которые ты хочешь использовать реализуют этот интерфейс (или наследуются от нужного базового класса). Т.о. при создании нового класса, который должен использоваться твоим классом-менеджером нужно просто реализовать интерфейс или перекрыть нужные методы, и базовый класс трогать не надо. -------------------- // Любая сложная система - это темный лес. Каждый в этом лесу протаптывает свои тропинки, по ним и бегает. Лишь изредка, сходя с них, мы находим много интересного, а порою и страшного. |
|||
|
||||
| pseud |
|
|||
![]() Экспёрт Тыдыщ ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1175 Регистрация: 18.5.2007 Где: Минск, Беларусь Репутация: 10 Всего: 40 |
тогда переопределяй метод как я уже писал выше reintroduce. но тогда, используя метод Find в потомках, ты не сможешь использовать его в предыдущей интерпретации. т.е. твой код все равно не заработает Koster,
-------------------- Испытание чужого терпения можно считать успешным, если оно лопнуло... |
|||
|
||||
| Koster |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 6 Регистрация: 2.6.2008 Репутация: нет Всего: нет |
А можна ли сделать чтобы заработал таки? Или это я слишком много требую? |
|||
|
||||
| pseud |
|
|||
![]() Экспёрт Тыдыщ ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1175 Регистрация: 18.5.2007 Где: Минск, Беларусь Репутация: 10 Всего: 40 |
только если так:
-------------------- Испытание чужого терпения можно считать успешным, если оно лопнуло... |
|||
|
||||
| Beltar |
|
||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 627 Регистрация: 11.1.2006 Репутация: 3 Всего: 7 |
Если я правильно понял, тут не ООП ИМХО применять надо, а ф-ии обратного вызова. И ничего наследовать не понадобиться. Как и создавать для каждого типа данных свой класс. Объявляй Find с параметром типа Integer или Pointer и суй него указатель на функцию поиска. Например так. У меня в одной софтинке есть TreeView и 2 способа сортировки узлов. Объявляю их так. Ни в коем случае не методы формы.
Или проще процедурный тип используй. -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. Пищущий на C++ мужик. Даже если это мужик сидит в написанном на Delphi и жрущем паскалевскую библиотеку билдере. |
||||
|
|||||
| pseud |
|
|||
![]() Экспёрт Тыдыщ ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1175 Регистрация: 18.5.2007 Где: Минск, Беларусь Репутация: 10 Всего: 40 |
Beltar, помоему ты не правильно понял вопрос.
т.е. есть класс TBase в каком-то dcu или еще где-то. и надо понасоздавать его потомков с теми же функциями/процедурами но иной реализацией. -------------------- Испытание чужого терпения можно считать успешным, если оно лопнуло... |
|||
|
||||
| Beltar |
|
||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 627 Регистрация: 11.1.2006 Репутация: 3 Всего: 7 |
Так где-то или в исходниках? Я вижу, что он показывает код TBase и пишет, что "так реализовал".
Т. е. мы немедленно знаем, что у нас в переменной. В этом случае вызов ф-ии обр. вызова наименее трудозатратный способ. Если бы имелся набор переменных TBase и в каждой неизвестный наследник, тогда конечно наследование. Помоему придется в базовом классе объявлять Find(Pointer); можно пусть даже под др. именами реализовать поиск для простейших типов и строк. Имхо это разумный компромисс. Из разряда той же overload. Кстати, а так ли нужно писать класс, когда можно понаделать миллион перегруженных ф-ий? Какой-то нездоровый подход попахивающий обшарпаным Ц. Это сообщение отредактировал(а) Beltar - 5.6.2008, 11:18 -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. Пищущий на C++ мужик. Даже если это мужик сидит в написанном на Delphi и жрущем паскалевскую библиотеку билдере. |
||||
|
|||||
| Koster |
|
||||
|
Новичок Профиль Группа: Участник Сообщений: 6 Регистрация: 2.6.2008 Репутация: нет Всего: нет |
Перед вызовом функции a.find(5.7) для компилятора еще неизвестно какой именно тип параметра передается. В этом то и проблема, потому то и был использован тип variant. А потом в методе find, который является статическим, с помощью абстрактной функции ItemToPointer динамически создается переменная в памяти нужного типа (потомок то знает что там должно быть), записывается туда входной параметр и возвращает в метод find указатель. А find уже сам потом ищет среди таких же нетипизированных указателей нужный элемент. Для сравнения двух указателей используется, опять же абстрактный, метод cmp, который проверяет равны ли значения хранящиеся в этих указателях, и возвращает результат в типе integer.
Миллион перегруженных функций, ИМХО, это некрасиво. Я пока учусь, но приведу пример почему, ИМХО, это некрасиво: Например, программу пишут несколько человек, один человек делает этот класс и паралельно этот же класс (пока несуществующий, но уже известен его интерфейс) используется другим человеком. Предположим что второму человеку пришлось добавить новый тип для данного класса. Тут есть два варианта: 1. Он берет, и переделывает у себя базовый класс, получается две версии класса. Лично мне кажется это не правильным, да к тому же невозможно если этот класс еще недописан. 2. Он говорит первому программисту чтобы тот добавил новый перегруженный метод. Но в таком случае, если нужно что то подправить, нужно опять же идти к первому программисту и портить ему нервы. А потом первому программисту пришла в голову невероятно умная мысль, он вспомнил что сортировка "пузырьком" не самая эффективная и начал делать квик сорт. А у него есть миллион перегруженных методов, в которых заново сделана сортировка, и везде надо поменять ее на новую. Может если первому программисту платят за время работы а не результат, то он даже рад будет. А если нет? Если же писать через классы, тогда для того чтобы добавить второму программисту новый тип, достаточно написать новый класс и реализовать в нем нужные виртуальные методы. Ему даже не нужен тот базовый класс для этого, достаточно заглушки с ограниченым функционалом. Если я не прав в организации работы программистов в группе, подправьте. |
||||
|
|||||
| Felan |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 284 Регистрация: 2.8.2007 Где: Самара Репутация: 2 Всего: 7 |
Прав, прав... и я тебе уже объяснил, как надо поступать в таких случаях. А ты все пытаешься "обработать напильником" то, что не предназначено для твоей идеи. -------------------- // Любая сложная система - это темный лес. Каждый в этом лесу протаптывает свои тропинки, по ним и бегает. Лишь изредка, сходя с них, мы находим много интересного, а порою и страшного. |
|||
|
||||
| Beltar |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 627 Регистрация: 11.1.2006 Репутация: 3 Всего: 7 |
Проблема у тебя в том, что нельзя объявить перекрываемый метод с другим набором параметров. Проще всего сделать его с пойнтером. Если у тебя ищутся сложные структуры данных, то это единственный вариант. С элементарными типами это конечно неудобно и ты не сможешь вызвать a.find(5.7), но элементарных типов-то кот наплакал. LongInt, Cardinal, Extended, String, ну можно и ShortString вспомнить. 3-4 перегруженных ф-ии для них, как тебе советуют, это не проблема. И что-то я не совсем понимаю, кому может понадобиться искать отдельные числа. А строки можно хранить в наследнике TStrings.
У меня еще такой вопрос: А где сами данные-то лежат? Ну допустим все свалены в TList т. е. в простом массиве указателей. Как их различать-то? Так приходим или к контейнеру для строго определенного типа или создаем еще набор классов для хранения данных. Что вообще делает твоя софтина? Это сообщение отредактировал(а) Beltar - 6.6.2008, 11:23 -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. Пищущий на C++ мужик. Даже если это мужик сидит в написанном на Delphi и жрущем паскалевскую библиотеку билдере. |
|||
|
||||
| pseud |
|
||||||
![]() Экспёрт Тыдыщ ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1175 Регистрация: 18.5.2007 Где: Минск, Беларусь Репутация: 10 Всего: 40 |
Koster,
ты, я думаю, уже успел поработать с такими чудными компонентами дельфи как компоненты для работы с БД. имеем конструкцию:
смотрим ее реализацию:
ай ай ай, как же так. а так. это дело реализовано в TIntegerField:
А зачем они так сделали? ООП блин. все объявили в базовом TField. А реализовали в соответствующих потомках. Думаю и тебе не стоит чураться такой практики. -------------------- Испытание чужого терпения можно считать успешным, если оно лопнуло... |
||||||
|
|||||||
| Koster |
|
||||||||||||||||
|
Новичок Профиль Группа: Участник Сообщений: 6 Регистрация: 2.6.2008 Репутация: нет Всего: нет |
Зря думаешь
У меня именно так все и реализовано. Для полной ясности приведу полный интерфейс своих классов, если кому то не лень будет разбираться. Это задание было у меня на курсовой по ООП. Я ее сдал с вариантами, никаких претензий небыло. Но я хочу, чисто для себя, понять как это можна реализовать универсальнее. Вот базовый класс:
А вот пример интерфейса потомка:
Это должно было быть что то на подобие шаблонов в плюсах, естественно гораздо урезаннее по функционалу (пока) и медленнее (так как обрабатывается не компилятором). Но есть и преимущества: можна переинициализовывать одну переменную для разных типов, чего в плюсах делать, как я помню, нельзя. Опишу ту часть которая интересует больше всего: это метод find. Он в базовом классе реализован вот так:
Тут видно что все хранится в TList, т.е. в безтиповых указателях. Метод ConstToPointer - абстрактный метод задача которого получить вариант, и перевести его в такой же безтиповый указатель как и остальные элементы TList. Он состоит из таких строк:
Можно было бы сделать find виртуальным и в каждом потомке его дополнять. Но мне показалось так удобнее. Еще один абстрактный метод, который играет очень важную роль - это cmp. Он на вход получает 2 указателя, а потом сравнивает их содержимое. Вот его реализация для TIntArray:
Тут все просто. Остальные методы класса TBaseArray мало относятся к методу find. Насчет перегрузки функций, я думаю что так и буду делать. Тогда еще такой маленький вопрос. А можна ли перегружать свойства?
Это сообщение отредактировал(а) Alexeis - 7.6.2008, 11:09 |
||||||||||||||||
|
|||||||||||||||||
| Beltar |
|
||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 627 Регистрация: 11.1.2006 Репутация: 3 Всего: 7 |
А зачем тогда ООП, если все подряд в наследнике переписывать?? В protected надо было объявить. И что метод Find ищет-таки? Перебирает указатели, считая, что они определеного типа. Ну допустим у тебя запихан туда Integer, а ты ищешь Double. Внимание вопрос, а кому принадлежат еще 4 байта идущие после целого и что произойдет когда программа попытается их прочитать? Вот что-то мне подсказывает, что так можно и AV схлопотать.
Зачем использовать on, Если ты все равно не проверяешь тип исключения? -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. Пищущий на C++ мужик. Даже если это мужик сидит в написанном на Delphi и жрущем паскалевскую библиотеку билдере. |
||||
|
|||||
![]()
|
| Правила форума "Delphi: Общие вопросы" | |
|
|
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | Delphi: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |