TList проблема создания

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Re: TList проблема создания

Сообщение Alex2013 » 19.12.2022 03:11:33

Хм ... Возможно вы правы, но как-то это странно (я такого "присвоения типа" еще нигде не видел ) .
А почему по "логике паскаля" нельзя присвоить переменной тип ? Потому что операция "присвоить" подразумевает передачу данных, а что собственно передается в случае "присвоения типа" ?
Код: Выделить всё
CreateControl(TEdit, 'Edit1', 10, 10, 100, 20);   

Параметр "это другое" там дальше может быть обычное сравнение typeOf который "Возвращает указатель на VMT объекта". А вы пытаетесь "подменить" одну возможно вообще статически описанную структуру на другую.
Последний раз редактировалось Alex2013 19.12.2022 06:19:17, всего редактировалось 1 раз.
Alex2013
долгожитель
 
Сообщения: 2943
Зарегистрирован: 03.04.2013 11:59:44

Re: TList проблема создания

Сообщение Seenkao » 19.12.2022 05:58:10

Тема: "когда коту заняться нечем"?
Seenkao
энтузиаст
 
Сообщения: 502
Зарегистрирован: 01.04.2020 03:37:12

Re: TList проблема создания

Сообщение Alex2013 » 19.12.2022 06:23:19

Seenkao писал(а):Тема: "когда коту заняться нечем"?

Нет например мне реально интересно можно-ли штатно "присвоить тип" и не вылезет ли где-то боком подобное "оригинальное творчество" .
Alex2013
долгожитель
 
Сообщения: 2943
Зарегистрирован: 03.04.2013 11:59:44

Re: TList проблема создания

Сообщение Юрий » 19.12.2022 07:59:37

Alex2013 писал(а):Хм ... Возможно вы правы, но как-то это странно (я такого "присвоения типа" еще нигде не видел ) .
А почему по "логике паскаля" нельзя присвоить переменной тип ? Потому что операция "присвоить" подразумевает передачу данных, а что собственно передается в случае "присвоения типа" ?
Код: Выделить всё
CreateControl(TEdit, 'Edit1', 10, 10, 100, 20);   

Параметр "это другое" там дальше может быть обычное сравнение typeOf который "Возвращает указатель на VMT объекта". А вы пытаетесь "подменить" одну возможно вообще статически описанную структуру на другую.

>>вообще статически описанную структуру
Ну ведь она тоже в той же памяти, над которой у вас есть “абсолютный” контроль на чтение по крайней мере

>>а что собственно передается в случае "присвоения типа" ?
все очень банально - указатель (даже не типизированный) ... Указатель на тип — это тот же указатель, который идет первым “полем” во внутренностях любого объекта. Внутри там будет таблица VMT и другие потроха...

Посмотрите, там схема на картинке, все коротко ясно…
http://bourabai.ru/einf/Delphi/Delphi_p ... dex11.html

Добавлено спустя 3 минуты 15 секунд:
Alex2013 писал(а):
Seenkao писал(а):Тема: "когда коту заняться нечем"?

Нет например мне реально интересно можно-ли штатно "присвоить тип" и не вылезет ли где-то боком подобное "оригинальное творчество" .

Я думаю, что вы сами сможете ответить на этот вопрос
Юрий
новенький
 
Сообщения: 11
Зарегистрирован: 03.04.2022 03:32:16

Re: TList проблема создания

Сообщение wavebvg » 19.12.2022 11:39:25

Юрий писал(а):Я считаю что это бага в FP
так как вся суть и прелесть использования Типа_ссылки_на_класс теряется


Не понятно, в чем баг-то? Использовать TClass для создания экземпляра класса использующего делегацию, по сути, явная ошибка.
Да, можно было бы в реализации FPC-го TList-а использовать проверку на nil, но что это даст? Не даст по рукам экспериментатору? Да, я бы ожидал, что экспериментатор, после получения ошибки, изучит предмет и решит проблему правильно, а не родит AV в самый неожиданный момент и порчу не аллоцированных для класса данных (это я про TList(theClass.Create).Create).

Чтобы по канонам все сделать, нужно:

1. Объявить конструктор виртуальным у TList

Код: Выделить всё
type
  TVList = class(TList)
  public
    contructor Create; virtual;
  end;


2. Объявить ссылку на класс:

Код: Выделить всё
type
  TVListClass = class of TVList;


3. Тогда можно смело использовать, к примеру так:

Код: Выделить всё
procedure AAA;
var
  theClass: TVListClass;
  L: TList;
begin
  theClass := TVList;
  L := theClass.Create;
  try
    ShowMessage(L.ClassName);   
    if L.Count = 0 then
      L.Add(nil);
  finally
    L.Free;
  end;
end;
wavebvg
постоялец
 
Сообщения: 354
Зарегистрирован: 28.02.2008 04:57:35

Re: TList проблема создания

Сообщение Alex2013 » 19.12.2022 14:07:03

1 Упс! Что за "AnObject is TObjectType" ?
2 Более менее понял, но как по мне проще и надежнее приводить уже созданный экземпляр к нужному базовому классу ( что работает отлично если они совместимы в цепочке наследования и имеют виртуальные методы) .
То есть L:= TList.Create; и если это где-то нужно theClass := TClass(L);
( или theClass := ( TList.Create As TClass ); ) Да где-то возможно придется проверить TypeОf но обычно это не проблема (+ (ИМХО) все явно и не проблемы "с неприсвоенным типом" и т.п. ).
И более того приведение типов в отличии от "присвоения типа" работает "в обе стороны цепочки наследования" (Разумеется, в этом случае нужно быть уверенным, что "хитроумно вызываемый метод" может обратится к реально существующим данным, но это точно работает ).
Alex2013
долгожитель
 
Сообщения: 2943
Зарегистрирован: 03.04.2013 11:59:44

Re: TList проблема создания

Сообщение wavebvg » 19.12.2022 16:09:40

Alex2013 писал(а):1 Упс! Что за "AnObject is TObjectType" ?
2 Более менее понял, но как по мне проще и надежнее приводить уже созданный экземпляр к нужному базовому классу ( что работает отлично если они совместимы в цепочке наследования и имеют виртуальные методы) .
То есть L:= TList.Create; и если это где-то нужно theClass := TClass(L);
( или theClass := ( TList.Create As TClass ); ) Да где-то возможно придется проверить TypeОf но обычно это не проблема (+ (ИМХО) все явно и не проблемы "с неприсвоенным типом" и т.п. ).
И более того приведение типов в отличии от "присвоения типа" работает "в обе стороны цепочки наследования" (Разумеется, в этом случае нужно быть уверенным, что "хитроумно вызываемый метод" может обратится к реально существующим данным, но это точно работает ).


Не надо ничего никуда "приводить". Обычно такие действия приводят к ошибкам

Изображение

, неподдерживаему коду и отвратительному стилю: срытию невоспроизводимых ошибок и т.п. (хотя строгий ММ помог бы очень быстро локализовать точки некорректного доступа к памяти, но всем пофигу)

Существует 3 варианта действий, когда используется явное приведение типов:

1. Если нужны свойства "дружественных классов" для доступа к protected (иногда даже в private) секции при делегации: создаёте класс пустышку. На крайний случай реализуете в нем пару методов (что нужно крайне редко). В остальных случаях хелперы.
2. Если Вы точно знаете, что нужный тип в коллекции. Сейчас есть худо-бедно генерики, которые эту необходимость почти полностью исключают.
3. Если Вы предварительно проверили is (использовать as в этом случае смысла нет)

Другие случаи использования хардкста просто притянуты за уши.
wavebvg
постоялец
 
Сообщения: 354
Зарегистрирован: 28.02.2008 04:57:35

Re: TList проблема создания

Сообщение Alex2013 » 20.12.2022 05:15:09

1 Никаких ошибок "нет и быть не может" если достоверно известен код вызываемого метода ( особенно если это полностью самостоятельно написанное с нуля "дерево классов".
2 "Приведение типов" базовая фишка lcl используется повсеместно. Объясните например что может "пойти не так" например в случае такого кода

Код: Выделить всё
Var E:TWinControlEnumerator;
begin
E:=GetEnumeratorControls;
while e.MoveNext do
begin
if TypeOf(e.Current) = TypeOf(Panel1) then TPanel(e.Current).Hide;
end
end;

Прикол в том что Panel1 может быть совершенно "левым" потомком класса TPanel ( у меня в программе откуда взят фрагмент все просто "Panel1:TPanel" но это необязательное условие ) где метода Hide или не существует или он кроме того что "прячет панель" делает еще "что-то лишнее" ( например зачем-то сбрасывает данные в полях ввода или там "обнуляет картинку" ). Разумеется нужно быть совершенно уверенным в том что TPanel(e.Current).Hide; сработает именно "так как вам надо" но сам принцип работает железно.
Alex2013
долгожитель
 
Сообщения: 2943
Зарегистрирован: 03.04.2013 11:59:44

Re: TList проблема создания

Сообщение wavebvg » 20.12.2022 11:49:42

Код: Выделить всё
if TypeOf(e.Current) = TypeOf(Panel1) then TPanel(e.Current).Hide;

Такой код предполагает полное совпадение классов, т.е. вот так:
Код: Выделить всё
if e.Current.ClassType = Panel1.ClassType then TPanel(e.Current).Hide;

Что тоже странно, потому что Panel1 может быть любого класса не обязательно TPanel.

Логичный вариант вот такой:
Код: Выделить всё
if e.Current is TPanel then TPanel(e.Current).Hide;

Что у меня перечислено как 3й допустимый случай хардкастов.

ЗЫ Надеюсь это код не из реального проекта...
wavebvg
постоялец
 
Сообщения: 354
Зарегистрирован: 28.02.2008 04:57:35

Re: TList проблема создания

Сообщение Alex2013 » 20.12.2022 21:21:32

Главное, то что это фрагмент работает !
( То что можно сделать лучше (или просто "по другому") я нисколько не сомневаюсь )
Зы
С "is" разумеется красивее ( но лучше ли это?).
Зы Зы
"Реальный-не реальный" тут неважно (это из техно-демки с ОpenGL / ОpenVR и со "стандартным GUI" признаюсь там я особо не заморачивался , сам фрагмент разумеется "обрезан для ясности" и нашёл я его "по TypeOf", искать где у меня в проектах более цивильно (или необычно) "приводятся классы " слишком муторно, а "сочинять пример" с нуля лень ) Важно, что похожий код встречается в LCL ( и не только) и довольно часто .
Alex2013
долгожитель
 
Сообщения: 2943
Зарегистрирован: 03.04.2013 11:59:44

Re: TList проблема создания

Сообщение wavebvg » 21.12.2022 11:07:52

Alex2013 писал(а):Главное, то что это фрагмент работает !


Можно я поправлю "Главное, то что это фрагмент иногда работает"

А внешних изменений он может вообще не пережить.

Alex2013 писал(а):С "is" разумеется красивее ( но лучше ли это?).


Сила не в красоте, а в правоте )))

Код, в котором вначале сравниваются типы двух объектов, а потом кастуется тип, не прописанный контрактом для ранее использованных объектов, может привести к ошибкам, порче кучи и вообще апокалипсису мирового масштаба. Даже если сейчас работает.

Alex2013 писал(а):похожий код встречается в LCL ( и не только) и довольно часто


Не встречается (хотя охотно верю, что когда-то мог и быть, но нынче LCL не такая падучая стала...)
wavebvg
постоялец
 
Сообщения: 354
Зарегистрирован: 28.02.2008 04:57:35

Re: TList проблема создания

Сообщение Alex2013 » 21.12.2022 12:07:16

wavebvg писал(а):Можно я поправлю "Главное, то что это фрагмент иногда работает"

Лично я не представляю, что там может "не сработать".
( Хотя каюсь, как я сечас вспоминаю написано это недоразумение было чисто из лени, :oops: если я верно помню тамошнюю логику можно было просто сделать переменную CurrentPanel:TPanel или (CurrentPanels:Tlist для случая с несколькими панелями ( или как вариант создавать панели динамически в рун-тайм ) ) но это-же надо добавлять что-то в каждый обработчик и вообще следить за состоянием CurrentPanel(s), а так "тяп ляп и готово" (при выброе элемента ListBox нужная панель появляется, а для нормальной работы "повторного выбора" на входе в процедуру выбора вначале тупо "гасятся" все панели без разбора ) :wink: )

Но это все лирика, а суть в том что применение TPanel(e.Current).Hide; в данном контектсе вполне оправдано.
( Как там проверяется соответствие типов дело десятое, важно то что заранее тип неизвестен и e.Current выдает нечто типа TControl или вообще TObject )
Alex2013
долгожитель
 
Сообщения: 2943
Зарегистрирован: 03.04.2013 11:59:44

Пред.

Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 20

Рейтинг@Mail.ru