Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.119.139.59] |
|
Сообщ.
#1
,
|
|
|
Зачем родители тащат за собой виртуальные методы родителей?
Я бы понял, если бы вот это работало: type TX = class procedure A; virtual; end; TY = class(TX) procedure A; override; end; procedure TX.A; begin WriteLn('TX.A') end; procedure TY.A; begin WriteLn('TY.A') end; var Y: TY; begin Y := TX.Create; // Incompatible types: 'TY' and 'TX' Y.A; Y.Free; Y := TY.Create; Y.A; Y.Free end. Если мы уберём выделенный красным текст, мы увидим в коде TX.A и TY.A, хотя TX.A никогда(!) не вызывается!!! Если же мы уберём слова virtual и override, то увидим в коде только TY.A, что логично. Вопрос: зачем виртуальные методы тащат за собой методы родителей? |
Сообщ.
#2
,
|
|
|
Цитата Jin X @ зачем виртуальные методы тащат за собой методы родителей? потому что для любой более менее сложной программы в компил тайм практически невозможно понять, вызываются ли виртуальный метод предка. Простейший вариант var Y: TY; begin Y := TY.Create; try PPointer(Y)^ := Y.ClassType.ClassParent; Y.A; finally Y.Free; end; end; |
Сообщ.
#3
,
|
|
|
Ясно. Спасибо
|
Сообщ.
#4
,
|
|
|
Цитата Jin X @ Вопрос: зачем виртуальные методы тащат за собой методы родителей? Затем, что ты "суслика не видишь (ссылку на виртуальный метод родителя), а он есть!" Указатели на виртуальные методы хранятся в структуре VMT класса, которая также должна содержать указатель ClassParent на VMT родительского класса, которая в свою очередь содержит указатели на все виртуальные методы родителя - а раз есть указатели\ссылки на методы, то ес-но д.б. и сами методы. Соотв-но в коде сохраняется цепочка VMT всех родительских классов до TObject и все их виртуальные и динамические методы. |
Сообщ.
#5
,
|
|
|
Цитата leo @ Да, это я знаю, просто не знал, что можно родителя получить... Указатели на виртуальные методы хранятся в структуре VMT класса |
Сообщ.
#6
,
|
|
|
Вообще, я к тому, что очень много порожняка лежит в EXE-шниках. Понятно, что уже не те времена, когда несколько сотен килобайт имеют большое значение, но всё же хотелось бы чистоты кода.
Конечно, использование ClassParent сложно отследить (можно самому в VMT залезть и стырить оттуда, если очень надо), но... Если бы, например, все unit-ы перекомпилировались (или хранились в виде сжатого исходника или байт-кода, как вариант, а не откомпилированного кода и т.п.), а в процедурах и функциях была бы проверка (в очевидных местах, по крайней мере) - используется ли какое-то значение, которое может сильно усложнить конструкцию, типа: procedure X(A: Boolean = True); begin // Бла-бла-бла if not A then begin // И вот тут никому не нужное мясо end end; begin X end. Добавлено А может, я чего не знаю, и есть какие-то конструкции типа (условно): procedure X(A: Boolean = True); separate code if A then begin end else begin end; Т.е. фактически это 2 отдельные процедуры, под которые написано 2 разных кода. И в зависимости от значения A вызывается одна процедура или другая. Если A - это переменная, то делается if перед вызовом |
Сообщ.
#7
,
|
|
|
Это называется inline. Пометь процедуру X словом inline и если компилятор сумеет заинлайнить метод, то в EXE останется, только тот код,который реально используется
|
Сообщ.
#8
,
|
|
|
Т.е. если я напишу:
procedure XforTrue; ... procedure XforFalse; ... procedure X(A: Boolean); inline; begin if A then XforTrue else XforFalse end; |
Сообщ.
#9
,
|
|
|
Не, inline тут ни при чем. Как можно убирать код, определяемый переменной? А вот точно неиспользуемые куски линкер режет хорошо.
Что касается вирт методов - то же самое. Они м.б. использованы в рантайме динамически, потому на всякий случай тащатся в бинарник все. Иначе никак. А вот обычные методы тоже очень хорошо режутся в случае неиспользования. P.S. Если так пробило на оптимизацию - посмотри, какими костылями заменяли вирт методы в KOL. |
Сообщ.
#10
,
|
|
|
Цитата Fr0sT @ Так, тут как раз пример БЕЗ ПЕРЕМЕННОЙ...Не, inline тут ни при чем. Как можно убирать код, определяемый переменной? Цитата Fr0sT @ Лучше расскажи - это будет точно быстрее и проще P.S. Если так пробило на оптимизацию - посмотри, какими костылями заменяли вирт методы в KOL. |
Сообщ.
#11
,
|
|
|
Цитата Fr0sT @ Не, inline тут ни при чем. inline тут при всём. только после инлайна можно можно попробовать убрать части метода |
Сообщ.
#12
,
|
|
|
Цитата Jin X @ Так, тут как раз пример БЕЗ ПЕРЕМЕННОЙ... А это что? Цитата X(A: Boolean = True) Цитата Jin X @ Лучше расскажи - это будет точно быстрее и проще Цитата Разработчики KOL/MCK сумели предложить компромиссное решение, дающее аналог VCL с возможностью визуального проектирования, но с выходным размером исполняемого модуля в 5-10 раз меньше, чем с VCL. Здесь сыграли свою роль и оптимизация многих участков на ассемблере, и интересное решение с фактическим отказом от наследования в традиционном смысле: все визуальные компоненты KOL являются экземплярами единого огромного TControl, реализующего функциональность сразу всех интерфейсных элементов ОС. Можно говорить, что решение KOL — это ОО-надстройка над описателем окна (handle) «в лоб», не делающая различий между разными классами элементов интерфейса, как не делает их сама ОС. https://ru.wikipedia.org/wiki/KOL Цитата jack128 @ inline тут при всём. только после инлайна можно можно попробовать убрать части метода C тем же успехом их можно убирать и без инлайна. Дело-то не в нем, а в том, что ветка, доступность которой не определяется однозначно на этапе компиляции, не м.б. выкинута. |
Сообщ.
#13
,
|
|
|
Цитата Fr0sT @ Это переменная-параметр процедуры, но при вызове процедуры переменная же не передаётся, передаётся заранее известная константа. Поэтому компилер, раскрывая inline, будет знать как будут разворачиваться события (что будет на выходе if'а) А это что? Цитата Fr0sT @ Так, это и ежу понятно Я же привёл пример, где можно.ветка, доступность которой не определяется однозначно на этапе компиляции, не м.б. выкинута. Я ща попробую, собственно, компильнуть... Добавлено Да, jack128 прав, так и есть! По крайней мере, в Берлине. Вот не знаю, в 2005 так же или нет? Есть у кого возможность компильнуть на 2005 и глянуть внутрь наличие срок FFFFFFFFFFFFFF и TTTTTTTTTTTTTT (или дебагером посмотреть ассемблерный код) {$APPTYPE CONSOLE} procedure XT; begin WriteLn(AnsiString('TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT')) end; procedure XF; begin WriteLn(AnsiString('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF')) end; procedure X(A: Boolean = True); inline; begin if A then XT else XF end; begin X end. |
Сообщ.
#14
,
|
|
|
Цитата Fr0sT @ C тем же успехом их можно убирать и без инлайна. Теоретически, в параллельной вселенной. На практике ДЕЛЬФИ умеет убирать куски кода только после инлайна. |
Сообщ.
#15
,
|
|
|
Цитата Jin X @ при вызове процедуры переменная же не передаётся, передаётся заранее известная константа А, ты имел в виду, что в программе только один вызов с заранее определенным значением параметра... всё, понял, о чем речь. Да - это не так уж отличается от вырезания const foo=1; begin if foo = 2 then msgbox('lala'); И в XE2 это работает (только с inline). Цитата jack128 @ На практике ДЕЛЬФИ умеет убирать куски кода только после инлайна. Такие - да, с остальными проблем нет. |