На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела:
1. Название темы - краткое описание кто/что против кого/чего
2. В первом сообщении - список параметров, по которым идет сравнение.
3. Старайтесь аргументировать свои высказывания. Фразы типа "Венда/Слюникс - ацтой" считаются флудом.
4. Давайте жить дружно и не доводить обсуждение до маразма и личных оскорблений.
Модераторы: Модераторы, Комодераторы
Страницы: (3) 1 [2] 3  все  ( Перейти к последнему сообщению )  
> [Delphi] Методы vs функции, классовые vs статик методы и всё остальное.
    Цитата DelphiLexx @
    я не хочу отделять ф-цию Compare от класса, мне не хотелось бы в моем классе, у которого есть метод Sort, чтобы он использовал вещи лежащие вне класса.
    ...не граммотно это

    Глупости. Так можно дойти до того, что и функции из модулей StrUtils, Math и т.п. нельзя использовать, поскольку они не принадлежат классу :)

    Во-первых, можно просто функции сравнения дать осмысленное название (типа CompareTMyListItems) и разместить ее в implementation рядом с твоим Sort. Ничего страшного или неграмотного в этом нет - "я так тыщу раз делал" (С)
    Во-вторых, функция сравнения должна быть "глобальной" по сути, а не формально. Т.е. это может быть и вложенная функция внутри самой Sort при условии, что она не будет обращаться к локальным переменным функции Sort (включая Self и его поля). Пример:
    ExpandedWrap disabled
      type
        TMylist = class(TList)
        public
          procedure Sort(Desc:boolean = false);overload;
        end;
      procedure tMyList.Sort(Desc:boolean = false);
        //вложенные функции сравнения
        function CompareAsc(Item1,Item2:pointer):integer;
        begin
          result:=integer(Item1)-integer(Item2);
        end;
        function CompareDesc(Item1,Item2:pointer):integer;
        begin
          result:=integer(Item2)-integer(Item1);
        end;
      begin
        if Desc then
          Sort(@CompareDesc)
        else
          Sort(@CompareAsc);
      end;
       
      procedure TForm1.Button1Click(Sender: TObject);
      var
        L:TMyList;
        S:string;
        i:integer;
      begin
        L:=TMyList.Create;
        try
          L.Add(pointer(2));
          L.Add(pointer(1));
          L.Add(pointer(3));
          L.Sort;
          S:='';
          for i:=0 to L.Count-1 do
            S:=S+IntTostr(integer(L[i]));
          L.Sort(true);
          S:=S+#13#10;
          for i:=0 to L.Count-1 do
            S:=S+IntTostr(integer(L[i]));
          ShowMessage(S);
        finally
          L.Free;
        end;    
      end;
    Сообщение отредактировано: leo -
      Felan кошмар, ужос!!!!!!!!!!!!!! У тебя же глобальная функция!!!!!!!!!!!!!

      Добавлено
      Цитата leo @
      то она не будет обращаться к локальным переменным функции Sort

      кста, немного по извращавшись с асмом можно сделать, чтоб она могла к локальным переменным обращаться.
        Цитата Felan @
        Ну, если сделать доступ потокобезопасный к Sort, то можно так извращьнуться

        А вот ненужные глобальные переменные ИМХО это гораздо большее извращение, чем "глобальные" функции ;) Проще скопипастить реализацию QuickSort из Classes и переопределить функцию сравнения на метод.

        PS: Если метод нужен только для того, чтобы добраться до некоторого св-ва TMyList, то есть вариант использовать в элементах Item ссылку на список Parent:TMyList и в функции сравнения юзать
        if TMyItem(Item1).Parent.FSign then ...

        Цитата jack128 @
        кста, немного по извращавшись с асмом можно сделать, чтоб она могла к локальным переменным обращаться

        В отношении Sort шибко сомневаюсь, т.к. она использует рекурсивные вызовы QuickSort, в которую передается не сам TList, а только массив указателей. Поэтому уже на втором уровне вложенности все локальные переменные Sort улетят далеко-далеко ;)
        Сообщение отредактировано: leo -
          Цитата leo @
          В отношении Sort шибко сомневаюсь, т.к. она использует рекурсивные вызовы QuickSort, в которую передается не сам TList, а только массив указателей. Поэтому уже на втором уровне вложенности все локальные переменные Sort улетят далеко-далеко ;)


          Ну вот такой код:

          ExpandedWrap disabled
            procedure TForm3.Test;
            var
              LocalCounter: Integer;
              function LocalCompare(Item1, Item2: Integer): Integer;
              begin
                Inc(LocalCounter);
                Inc(GlobalCounter);
                Result := Item1 - Item2;
              end;
            var
              I: Integer;
              L: TList;
            begin
              Randomize;
              GlobalCounter := 0; LocalCounter := 0;
              L := TList.Create;
              try
                for I := 0 to 100 - 1 do
                  L.Add(Pointer(Random(100)));
                L.Sort(LocalProcCaller(@LocalCompare).Proc);  // вся магия в LocalProcCaller.  там динамически генерится код, подправляющий стек.
                Memo1.Lines.Clear;
                for I := 0 to L.Count - 1 do
                  Memo1.Lines.Add(IntToStr(Integer(L[I])));
                Memo1.Lines.Add(Format('LocalCount = %d, GlobalCounter = %d', [LocalCounter, GlobalCounter])) // LocalCount всегда равен GlobalCounter.  AV нигде нет. Сортируется тоже нормально..
              finally
                L.Free;
              end;
            end;


          Скажу чесно сам я в асме не силен, идею почерпнул из модуля AsyncCalls.pas. Если интересно могу выложить исходники LocalProcCaller, может багу кто найдет.
            jack128 ААААА!!!!!!!!!! Убей меня об стенку скореее!!!!!!!!!! :)

            Так-то да, но наследники то уже будут метод использовать, а не глобальную функцию, однажды и навсегда скрутую в нутри класса.

            leo Так ты самую вкусность скрыл. Теперь извне классу не подставишь "компоратор". Если раньше можно было для любого объекта сделать функцию сравнения, передать ее в список и он бы сортировал что угодно, то теперь только то, что ты пропишешь и ничего более.
              Может хватит, а? А то впечатление, что здесь одни извращенцы собрались.
              Функция сравнения, как я уже сказал, сделана именно функцией совсем не случайно. Можно было ее сделать методом класса, но не сделали потому, что контейнер TObjectList может хранить и "чужие" объекты, у которых метода сравнения нет и сделать нельзя (о хелперах не говорю).
                Цитата jack128 @
                вся магия в LocalProcCaller. там динамически генерится код, подправляющий стек

                Ну ежели динамически, то конечно ;) В таком случае можно и вызов метода из функции организовать наподобии MakeObjectInstance

                Цитата Felan @
                Так ты самую вкусность скрыл. Теперь извне классу не подставишь "компоратор". Если раньше можно было для любого объекта сделать функцию сравнения, передать ее в список и он бы сортировал что угодно, то теперь только то, что ты пропишешь и ничего более

                "Скрыл" только для примера, по заявкам трудящихся антиглобалистов :D
                К тому же за счет overloaded оригинальный Sort остается - подставляй, что хочешь

                Добавлено
                Цитата Romkin @
                Можно было ее сделать методом класса, но не сделали потому, что контейнер TObjectList может хранить и "чужие" объекты, у которых метода сравнения нет и сделать нельзя (о хелперах не говорю)

                Странное объяснение ;) Значит сравнивать "несравнимые" элементы разрешили (через функцию), но иметь при этом доступ к некому объекту (владельцу функции сравнения) - ни-изя ?!
                  Цитата leo @
                  Значит сравнивать "несравнимые" элементы разрешили (через функцию), но иметь при этом доступ к некому объекту (владельцу функции сравнения) - ни-изя ?!

                  А зачем и с какой целью? Тебе даны две сущности - их и сравни. Заодно при смене контейнера функцию менять не надо, она уже есть.
                  Каким образом результат сравнения двух сущностей может зависеть от экземпляра контейнера, в котором они содержатся?
                    Цитата Romkin @
                    Каким образом результат сравнения двух сущностей может зависеть от экземпляра контейнера, в котором они содержатся?

                    э-э-э. TStrings.CompareStrings например.
                      Цитата jack128 @
                      э-э-э. TStrings.CompareStrings например.

                      И шо? Там строки, все сразу понятно. И от контейнера тоже не зависит. Добавь к этому, что TStrings - абстрактный класс, ты обязан написать потомка.
                      А вот TStringList.CustomSort опять использует функцию, экземпляр в которую передается только потому, что неизвестно, какой элемент ты хочешь сравнивать, саму строку, или объект, и даются индексы. И для реализации сравнения не нужно писать потомка.
                      Это удобно и разумно. И криминала здесь никакого нет. Вообще.
                        Цитата Romkin @
                        И от контейнера тоже не зависит.

                        ну как же - смотрим его наследника, TStringLIst и что мы видим ?? Функция сравнения использует данные класса.
                          Цитата jack128 @
                          ну как же - смотрим его наследника, TStringLIst и что мы видим ?? Функция сравнения использует данные класса.

                          Хм. Действительно. Выбор нужной функции для сравнения.
                          Но абсолютно не мешает подать соответствующую функцию compare в Sort. Leo чуть выше практически это и сделал. Так что криминала все равно нет.
                          А вот если бы TList использовал свою виртуальную функцию, тебе пришлось бы на каждый чих писать его наследника.
                            Цитата Romkin @
                            А вот если бы TList использовал свою виртуальную функцию,

                            а никто этого и не предлагает. ПРедлагают чтоб List.Sort принемал не функцию, а метод.
                              Цитата Romkin @
                              Каким образом результат сравнения двух сущностей может зависеть от экземпляра контейнера, в котором они содержатся?

                              Во-первых, не обязательно самого контейнера, т.к. метод сравнения может принадлежать и не контейнеру, а любому другому объекту (например владельцу этого контейнера). Во-вторых, сущности могут сравниваться по разному и правило сравнения ес-но задают не сами сущности, а тот кто их сравнивает. Например, можно написать две разные функции сравнения для сортировки по возрастанию и по убыванию, а можно несколько поступиться быстродействием и впихнуть все в одну функцию, инвертирующую рез-т сравнения в завис-ти от некоторого св-ва самого контейнера или другого объекта.
                              В общем, задачи разные бывают и впадать из одной крайности (ха-ачу метод) в другую (ни-изя метод) - имхо не стоит :D
                                Цитата leo @
                                В общем, задачи разные бывают и впадать из одной крайности (ха-ачу метод) в другую (ни-изя метод) - имхо не стоит

                                А это не крайность, это вопрос удобства. В данном случае метод просто унаследован от TList, а там чаше всего требование именно метода ограничивает, мало ли на что я там ссылки хранить буду. А мотивов переделывать Sort на получающий метод я не вижу.
                                1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (3) 1 [2] 3  все


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0456 ]   [ 14 queries used ]   [ Generated: 17.07.25, 22:15 GMT ]