delphi just die when compile this code =)

Тема в разделе "WASM.HEAP", создана пользователем S_T_A_S_, 24 июн 2005.

  1. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    S_T_A_S_

    > „вместо того, чтобы сохранить New и Dispose заменили их на вызов myfoo:=foo.Create и myfoo.Free."

    >> "Речь идёт не о привычке, а о принципиальном различае этих ф-ций."



    Принципиального различия нет, т.к. они выполняют идентичные функции. Разница только в синтаксисе и в реализации - либо разные макросы либо замена макроса на функцию. Например Dispose(myfoo,Destroy) это макрос = myfoo.Destroy+Dispose(myfoo), где в свою очередь Dispose выполняет Finalize+FreeMem. А myfoo.Free это функция TObject.Free c параметром myfoo, передаваемым в регистр EAX. И делает она тоже самое - сначала вызывает myfoo.Destroy, а затем TObject.FreeInstance = Finalize+FreeMem. Примерно также обстоят дела и с макросами New и foo.Create, которые оба в итоге сводятся к цепочке GetMem+Initialize+Create(здесь Create - просто как процедура инициализации созданного экземпляра myfoo).
     
  2. alpet

    alpet Александр

    Публикаций:
    0
    Регистрация:
    21 сен 2004
    Сообщения:
    1.221
    Адрес:
    Russia
    leo

    В дополнение могу добавить, что типа class был введен для большего соответствия технологии COM (что означает большую двоичную совместимость с интерфейсами, чем у C++).



    [...]

    Задался вчера задачей сделать в классе метод который можно использовать как оконную процедуру. Сначала просто модифицировал эпилог с помощью ассемблера, что было не удобно, потом добился и чисто высокоуровневого результата (см. аттач). Вообще гибким в этом отношении конечно язык Delphi назвать нельзя. Намного проще (и надежнее!) создать обычную функцию и передавать в нее параметром собственно сам объект.

    [​IMG] _2128708557__WindowProc.zip
     
  3. _staier

    _staier New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2003
    Сообщения:
    738
    Адрес:
    Ukraine
    alpet



    попробуй юзать такие конструкты



    function TForm1.XWindowProc(msg, wParam, lParam: Integer): Integer;

    var

    hwnd: THandle absolute self;

    Rct: TRect;

    begin

    // hwnd := Integer (self);
     
  4. alpet

    alpet Александр

    Публикаций:
    0
    Регистрация:
    21 сен 2004
    Сообщения:
    1.221
    Адрес:
    Russia
    staier

    Это как раз не нужно - производится обмен - self присвается указатель на действительный экземпляр, а hwnd, собственно перед этим, описатель окна попавший в self. Иными словами - без дополнительной переменной в стеке, здесь никак :dntknw:



    Можно рассмотреть к примеру открытый прототип метода:
    Код (Text):
    1.  
    2. function XWindowProc (self: TForm1; msg, wParam, lParam: Integer): Integer; stdcall;
    3.  


    Все отличие - к переменной self в Delphi применяется неявное раскрытие области видимости. То же самое здесь можно сделать и с помощью оператора with, но явно. Другое дело в Си ++, пришлось бы использовать ссылку или указатель на экземпляр класса (обьектов там вроде нет), или производить коррекцию указателя this аналогичным кодом.
     
  5. _staier

    _staier New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2003
    Сообщения:
    738
    Адрес:
    Ukraine
    S_T_A_S_



    "да ты что, петька, вот же он"







    позвольте полюбопытствовать , а какие же тогда обьекты имет смысл аллоцировать в стеке?



    я понимаю, что вы , скорее всего ошиблись , поэтому ,указав, что это бред , поставил смайлик...

    однако ваш дальнейший флейм показывает

    мне кажется...

    возможно я ошибаюсь ...

    но вы не читаете не только чужие посты , но и свои ....
     
  6. _staier

    _staier New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2003
    Сообщения:
    738
    Адрес:
    Ukraine
    alpet

    ты прав
     
  7. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    alpet

    Ну при желании можно и вот так извратиться:



    function XWindowProc ({foo_self,}foo1,foo2,lParam,wparam,msg,hwnd: Integer):Integer; register;



    Здесь foo_self, foo1 и foo2 просто обозначают EAX, EDX и ECX, а остальное в стеке с учетом инверсного порядка передачи в register и stdcall. Ну ес-но foo_self это никакой не self и надо вытянуть настоящий self из hwnd, как ты и делаешь
     
  8. alpet

    alpet Александр

    Публикаций:
    0
    Регистрация:
    21 сен 2004
    Сообщения:
    1.221
    Адрес:
    Russia
    leo

    Оригинально!



    Кстати, вот сделал и на C++. Поправка - указателю this ничего присвоить не удастся - он же const (или есть хитрый низкоуровневой способ ?). См. аттач (пример получился куда как сложнее - функторы в C++ описываются коряво).



    [​IMG] _249805795__objwp.cpp
     
  9. _staier

    _staier New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2003
    Сообщения:
    738
    Адрес:
    Ukraine
    думаю, что в духе с++ лучше использовать friend
     
  10. alpet

    alpet Александр

    Публикаций:
    0
    Регистрация:
    21 сен 2004
    Сообщения:
    1.221
    Адрес:
    Russia
    staier

    Вопрос с this решается до колбасы просто:
    Код (Text):
    1.  
    2. if (IsWindow (iwnd))
    3.         self = (LPVOID) (__int64) GetWindowLong (iwnd, GWL_USERDATA);  
    4.     __asm
    5.     {  
    6.         mov eax, [self]
    7.         mov [this], eax
    8.     }
    9.  


    Так что зря они приписывают ему свойство const :)
     
  11. _staier

    _staier New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2003
    Сообщения:
    738
    Адрес:
    Ukraine
    mov eax, [self]

    думаю , это лишнее , так как после вызова GetWindowLong

    результат всё равно будет в eax



    и зачем (_int64)?



    ps. я так в дельфи получал доступ к приватным членам класса типа

    private

    iscomponentregistered:boolean;

    :derisive:
     
  12. alpet

    alpet Александр

    Публикаций:
    0
    Регистрация:
    21 сен 2004
    Сообщения:
    1.221
    Адрес:
    Russia
    staier





    Лень запретить некоторые warnings, что возникают без этого приведения типов. Что касается [self] ты конечно прав )
     
  13. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Кстати с некоторым изумлением обнаружил, что не только в object, но и в class можно объявлять несколько деструкторов. Это уж вовсе не понятно, т.к. в VMT единственное зарезервированное поле vmtDestroy - куда ж девать остальные ??? Действительно, фикция какая-то ...



    Еще откопал старые исходники с object'ами. Там New с конструкторами вызываются с любыми параметрами просто как макрос типа
    Код (Text):
    1. New(lpfoo,Init(arg1,arg2,..));
    2. или
    3. lpfoo:=New(pfoo,Init(arg1,arg2,..));
    4. где foo = object, pfoo = ^foo, lpfoo:pfoo
     
  14. alpet

    alpet Александр

    Публикаций:
    0
    Регистрация:
    21 сен 2004
    Сообщения:
    1.221
    Адрес:
    Russia
    leo

    Не фикция однако - зарезервированное поле означает не больше, не меньше указатель на виртуальный деструктор по умолчанию (т.е. тот что обьявлен в TObject).

    .................................................

    Если определить еще один виртуальный деструктор (даже с тем же самым именем Destroy) - компилятор выделит ему как и обычному виртуальному методу место в VMT, но при этом снабдит пролог вызовом BeforeDestruction, а эпилог ClassDestroy (чтобы деструктор выполнял деструкцию :)).

    Метод TObject.Free всегда будет обращаться к деструктору по умолчанию, поэтому если его не переопределить с помощью override, а создать заново - вызываться будет деструктор предка.

    ...............................................

    И о статических/стековых объектах - с использованием object это вполне возможно, только в плане скомпилированного кода можно получить и не обьект вовсе, а просто связанные код и данные. Следующий код посути эквивалентен объявлению двух глобальных переменных x и y, и работе с ними. Никакой конструкции и деструкции при этом не требуется:


    Код (Text):
    1.  
    2. type
    3.   TSomeObj = object
    4.    x, y: dword;
    5.    procedure    ShowSelf;
    6.   end;
    7.  
    8. { TSomeObj }
    9.  
    10. procedure TSomeObj.ShowSelf;
    11. begin
    12.  ShowMessage (format ('x=%d, y=%d', [x, y]));
    13. end;
    14.  
    15. var x: TSomeObj;
    16. procedure TForm1.Button1Click(Sender: TObject);
    17. begin
    18.  x.x := 50;   // 8 bytes of code !!!
    19.  x.y := 100;  
    20.  x.ShowSelf;
    21. end;
    22.  




    При обьявлении такого обьекта в стеке его тело просто размещается в стеке. Ну, а как разместить в куче уже показал leo. Прослеживается аналогия с структурами С++ - методы есть и данные есть. Переменная типа class (4 байтный указатель на экземпляр объекта) в некотором отношении эквивалентна типу PObject = ^TSomeObj.
     
  15. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    alpet

    > "а эпилог ClassDestroy (чтобы деструктор выполнял деструкцию :))"



    А-а, точно. Че-то видать у меня со времен TP отложилось в подкорке, что деструктор это просто процедура, а реальную деструкцию делает Free. Да ты прав, хоть "заботливые" борманы и не рекомендуют прямой вызов деструктора и я как "прилежный мальчик" придерживаюсь этого совета, но ClassDestroy компилятор вставляет именно после вызова деструктора. Сэнкс за уточнение-просветление ;)



    > "Прослеживается аналогия с структурами С++ - методы есть и данные есть"

    Да. И можно создавать потомков добавляя поля и методы, а также переопределять методы - хошь виртуальные, а хошь просто переписыванием. Хоть и не полноценный ООП, но штука - полезная
     
  16. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    staier >




    Ну дык ты же умный человек, мог бы догадаться, что это опечатка =)





    alpet >




    Зачем SetWindowLong? И оконную процедуру можно виртуальной сделать что бы перегружать в потомках класса и использовать один цикл выборки не все окна.



    [​IMG] 632894033__window.zip
     
  17. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    alpet >




    это не совсем то :) как, например, такое сделать:
    Код (Text):
    1.  
    2. class Counted_string
    3. {
    4.     UNICODE_STRING  str;
    5. public:
    6.     __forceinline Counted_string(const wchar_t * s)
    7.     {
    8.         str.Buffer = (wchar_t *) s;
    9.         str.Length = 0;
    10.         while( *s++ ) str.Length += sizeof(wchar_t);
    11.         str.MaximumLength = str.Length + sizeof(wchar_t);
    12.     }
    13.     UNICODE_STRING * operator &() { return &str; };
    14. };
     
  18. alpet

    alpet Александр

    Публикаций:
    0
    Регистрация:
    21 сен 2004
    Сообщения:
    1.221
    Адрес:
    Russia
    S_T_A_S_

    Класс конечно шикарный, работает - но создание псевдоуказателя This отход от идеи - смысл тогда какой Оконную процедуру в пределах класса определять?



    Конечно подход с виртуальным устроением процедуры обработки - грамотно с точки зрения ООП, но на деле приведет к тому что каждое сообщение будет приводить к вызову GetWindowLong, чего конечно хотелось бы избежать.



    Потом у тебя всегда осуществляется и вызов дефолтного обработчика - зачем ?



    Мне хочется разработать нормальную ОПП библиотеку (не VCL), с возможностями быстрого расширения. Поэтому хочется вообще найти лучший способ сохранения this/self.

    Как вариант приветсвуется наличие таблицы (или нескольких таблиц) обработчиков, через которую можно быстро (т.е. оптимизированным поиском) установить метод класса. Городить ее с помощью VMT при этом не хочется. Думается что-то вроде обычного массива пар - сообщение-обработчик.

    -----------------------------------------------------

    Касательно второго поста - мы здесь не holywar затеваем случаем? Я просто привел аналогию, скорее архитектурную, чем демонстрацию возможностей. Что можно, и что нельзя в том или ином языке разговор вообще безсмысленный, я свободно и с удовольствием на обоих программирую, хотя от обоих в свое время плевался из-за предубеждений класса - того-то нет - язык суксь.
     
  19. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    alpet >




    А где её ещё определять? Так ограничивается предел видимости.



    >




    Не вижу никаких проблем в этом. Я использую классы наслеованные от этого в игрушке, никаких видимых тормозов это не даёт.



    >




    window_procedure() перегружается в потомках, поэтому работает один цикл выборки сообщений на все окна. А dispatcher() будет вызывать свой для каждого окна обработчик.



    >




    Нет, я просто привёл абстрактный пример. Недавно переписывал одну прогу с С++ на паскаль, а потом на дельфи, и такие досадные мелочи меня достали :-( Какой тут holywar может быть, у Паскаля даже стандартов нет никаких.
     
  20. alpet

    alpet Александр

    Публикаций:
    0
    Регистрация:
    21 сен 2004
    Сообщения:
    1.221
    Адрес:
    Russia
    S_T_A_S_

    1. Мне во всяком случае был интересен более когда метод будучи оконной процедурой, не теряет связи с классом.

    2. Мне сам прием не нравиться, конечно выполнение GetWindowLong быстрое - всего то извлечь дв.слово из массива. Нужен другой в общем подход, не расходующий ресурс GWL_USERDATA.

    Сейчас думаю вообще о такой альтернативе - когда множество окон будет обслуживать один класс, что позволит не заводить на каждое окно по экземпляру класса (это то что мне в VCL сильно весьма не нравиться). Но вариант - обьект класса окна по требованию, как это сделано в MFC, наверное придется реализовывать всеравно.



    3. Это понятно что вызывается свой обработчик, но после него также вызывается DefWindowProc, независимо от того нужен ли этот вызов или нет.

    4. Мне как-то пришлось переводить неаккуратно написанную программу с VB на C++. Там было очень много кода такого типа:

    str = s001 + ", " + s002 + ", " ... + s255.

    Уморился оформлять это в параметры для sprintf :dntknw:

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