Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.219.236.62] |
|
Сообщ.
#1
,
|
|
|
Доброго времени суток. Начал разбираться с ООП и заблудился, суть проблемы такая: есть массив
DrawList: array of TF; Это список, который составляется одной процедурой и рисуется другой. Определение этого такое: type TF = class StrField: array of TStrField; IntField: array of TIntField; constructor Create(Name: string; ID: word); overload; virtual; end; type TT = class(TF) Font: TFont; Indent: word; FullText: TStringList; constructor Create(Name: string; ID: word); override; procedure Draw; end; type TypO = class(TF) Sprite: array of TSprite; constructor Create(Name: string; ID: word); override; procedure Draw; end; Все данные типа размера, координат, видимости и прозрачности записано в TIntField. Прошу поверить на слово, что так было надо. При составлении списка проблем не возникло. А в рисовании проблема. Для производительности делается проверка всяких мёртвых, пустых и отключенных объектов. И тут возникло Invalid class typecast в этих строчках: if DrawList[i] is TypO then begin if (DrawList[i].IntField[1].Value>0)and(DrawList[i].IntField[7].Value>0) then (DrawList[i] as TypO).Draw; end else begin if (drawList[i].IntField[1].Value>0)and((DrawList[i] as TT).FullText.Count<>0) then (DrawList[i] as TT).Draw; end; Тут as вообще нигде не работает. Подскажите, пожалуйста, почему? |
Сообщ.
#2
,
|
|
|
Либо вы пробуете сконвертировать неправильный тип либо пытаетесь сконвертировать несуществующий объект.
Добавьте проверку if DrawList[i] <> nil then |
Сообщ.
#3
,
|
|
|
а какое отношение выше приведенный код имеет к ООП?
1) наследование есть 2) полиморфизма нет 3) а самое главное нет абстрактных классов. он как бы есть. но как бы и нет для повишения читабельности кода и его упрощении: а) метод "Draw" сделай виртуальный+абстрактный в TF классе. б) решение рисовать или не рисовать нужно делать или в самом методе "Draw" (что не красиво) или вынести как отдельный метод. (например isDraw()) тогда конечный код процедуры будет выглядеть for item in DrawList do if item.isDraw() then item.Draw(); Добавлено ну и массив смотреться не особо красиво "DrawList: array of TF;" не проще ли использовать дженерики TList<TF>. они и по практичнее будут, и дефрагментацию массива не придется самому делать |
Сообщ.
#4
,
|
|
|
Цитата k.sovailo @ Тут as вообще нигде не работает. Подскажите, пожалуйста, почему? Потому, что DrawList[i] содержит ссылку, не равную nil и не приводимую ни к TypO, ни к TT. Либо это ссылка на объект TF, либо на удаленный объект, либо вообще какой-то мусор (например, за счет выхода индекса за пределы массива). Добавлено Цитата Pavia @ Добавьте проверку if DrawList[i] <> nil then Добавить, конечно, не помешает. Но в данном случае дело не в этом, т.к. ошибка возникает именно на операторе as, для которого nil является допустимым значением (nil as Х = nil). |
Сообщ.
#5
,
|
|
|
Спасибо всем, ошибку нашёл и она была очень дурацкой.
leoправ, по нужной ссылке лежал мусор. При составлении списка было не DrawList[i]:=T[j], а DrawList[i]:=@T[j]; Перед этим менял тип DrawList'a и собака осталась. Pavia, спасибо, проверку добавил, хотя она не спасла. ViktorXP, извините, вашим советом не воспользуюсь, так как проблема решилась. Можно ли тогда вопрос в догонку: а насколько вообще быстро работают переходы по ссылкам, вызов метода объекта по сравнению с вызовом процедуры и передачи объекта, проверка is по сравнению с добавлением Is_T_or_O в DrawList и подобное? Нужно ли всю эту красоту городить, если мне нужно максимально разогнать эту программу? |
Сообщ.
#6
,
|
|
|
Цитата насколько вообще быстро работают переходы по ссылкам, вызов метода объекта по сравнению с вызовом процедуры и передачи объекта, проверка is по сравнению с добавлением Is_T_or_O в DrawList и подобное? Достаточно быстро. У вас не должно быть с этим проблем. Цитата Нужно ли всю эту красоту городить, если мне нужно максимально разогнать эту программу? Хотите гоняться за скоростью - пишите на TASM-е, если пишите в ООП, тогда и пишите, как вы выразились, красоту. Выбирать ООП и пытаться изворачиваться ради скорости это как забивать гвозди шуруповёртом... |
Сообщ.
#7
,
|
|
|
Цитата VisualProg @ Хотите гоняться за скоростью - пишите на TASM-е, если пишите в ООП, тогда и пишите, как вы выразились, красоту. Выбирать ООП и пытаться изворачиваться ради скорости это как забивать гвозди шуруповёртом... Очень бескомпромиссное суждение. Далеко не любой код на асме будет эффективнее того, что генерит компилятор. Оптимизировать на асме надо учиться, и довольно долго. Цитата k.sovailo @ Можно ли тогда вопрос в догонку: а насколько вообще быстро работают переходы по ссылкам, вызов метода объекта по сравнению с вызовом процедуры и передачи объекта, проверка is по сравнению с добавлением Is_T_or_O в DrawList и подобное? Нужно ли всю эту красоту городить, если мне нужно максимально разогнать эту программу? Надо смотреть по ситуации, абстрактной оптимизации не бывает. Надо искать узкие места и их менять. Смотри в сторону профайлера. Как пример, по приведенному фраменту: is, насколько я помню, не очень эффективен. Плюс у тебя на каждую итерацию проверка полей, т.е. три if. Этого можно избежать разными способами: 1) как сказал Viktor - виртуальным методом, убираем as и значительно сокращаем основной цикл, однако добавляется переход по виртуальному методу CanDraw либо постоянный вызов Draw со встроенной проверкой - плюс читаемости, эффективность та же или даже в минусе 2) добавить поле ObjType к TF, где будут варианты: Empty - не рисовать, Text - тип TT, Sprite - тип TypO. Плюс понадобится отслеживать модификацию ключевых полей и соответственно изменение ObjType. Тогда цикл сведется к case DrawList[i].ObjType of Text: TT(DrawList[i]).Draw; Sprite: TypO(DrawList[i]).Draw; end; 3) Разделить списки объектов по типам, что уберет проверку is. 4) Не добавлять в списки объекты, которые не будут отрисовываться, что уберет два if Но прежде всего - надо смотреть, какие части кода выполняются часто и помногу. Глупо вылизывать то, что выполняется раз в час. |
Сообщ.
#8
,
|
|
|
Цитата Fr0sT @ Очень бескомпромиссное суждение. Далеко не любой код на асме будет эффективнее того, что генерит компилятор. Оптимизировать на асме надо учиться, и довольно долго. Так, мы рассматривали вызов методов и "переходы по ссылкам": Цитата k.sovailo @ а насколько вообще быстро работают переходы по ссылкам, вызов метода объекта по сравнению с вызовом процедуры и передачи объекта Fr0sT, лично я не знаю как их ускорить средствами ООП. Поэтому и говорю что гнаться за такой мелочью - это идти в те самые дебри делфячного TASM-а. Вопрос правда встаёт, зачем было начинать писать на делфях, если надо считать настолько мелкие операции... А то что оптимизация зависит от знаний и умений ТС, имхо, это очевидно, так же как очевидно что если он плохо пишет на структурном уровне, его код будет ещё хуже и медленнее чем те же is/as в ООП. |
Сообщ.
#9
,
|
|
|
Цитата k.sovailo @ а насколько вообще быстро работают переходы по ссылкам, вызов метода объекта по сравнению с вызовом процедуры и передачи объекта, проверка is по сравнению с добавлением Is_T_or_O в DrawList и подобное? 1) Не понятно, что имеется ввиду под "переходами по ссылкам" 2) На низком уровне вызов метода полностью эквивалентен вызову процедуры с передачей объекта (в первом неявном параметре) 3) Проверка по is довольно тормозная, поэтому использовать ее нужно по назначению, а именно проверять принадлежность объекта классу не в конце иерархии, а где-то в ее начале\глубине (когда другого выхода нет). А в твоем случае лучше использовать прямую проверку типа if DrawList[i].ClassType = TypO - по скорости это эквивалентно сравнению некого доп. поля ObjType с заданным значением, как предлагает Frost |
Сообщ.
#10
,
|
|
|
Цитата VisualProg @ Так, мы рассматривали вызов методов и "переходы по ссылкам": Вызов на Дельфи будет медленней разве что в случае виртуального метода, в остальном одинаково. Разве что действительно в том случае, когда неявный параметр объекта вытесняет параметр из регистра, и компилятор начинает использовать стек. Но это верно и по сравнению с обычной процедурой на Дельфи Цитата leo @ if DrawList[i].ClassType = TypO О! Здорово, что напомнил, я позабыл об этой фиче) |