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

    Я предложил с Name съехать на Uri. Но ты отвертелся, сославшись на "зависит от контекста". :) Мне просто интересно - что именно зависит. :)

    Цитата wind @
    Нужны примеры наследования от модифицируемой строки?

    Все тот же Uri, как модифицируемая сущность.

    Цитата wind @
    Кстати, вы ничего вразумительного не сказали о теле млекопитающего.

    Ты невнимательно читал:
    Цитата Flex Ferrum @
    Архитектор открыввает учебник по биологии. Наиболее полным образом описывает класс MammalBody и все. Больше, чем написано в этом учебнике, все равно никто предложить не сможет (иначе это будет революция в биологии). А MammalBody, разложенное на клетки, атомы и прочее - это, извините, уже совсем другие сущности.
      Цитата Flex Ferrum @
      Я предложил с Name съехать на Uri. Но ты отвертелся, сославшись на "зависит от контекста".

      Я не отвертелся. Uri я мог бы сделать строкой, если бы это был не какой-то глобальный класс и в некотором локальном контексте являлся бы строкой. Как Name :) Но я бы не стал возиться с модифицируемой строкой, это точно.

      Цитата Flex Ferrum @
      Ты невнимательно читал

      Я внимательно читал, просто это не ответ. Архитектор в принципе не может почерпнуть из учебника биологии что-либо, кроме внешнего вида и принципиального строения тела млекопитающего. Никаких интересующих вероятных пользователей деталей таким образом учтено не может быть в принципе. Кроме того, в зависимости от контекста, тело может обладать атрибутами и поведением, никак не проистекающими из учебника биологии. Если делать надстройки над данным классом, то у меня уже не получится воспользоваться какими-либо механизмами, реализованными для него. Например, если тело рассматривается как мясопродукт, то у меня не получится заставить некую машину, разделывающую тушку, заставить работать как иначе, чем заложено архитектором - он уже определил составные части, на которые следует её делить. Форменный идиотизм получается :)

      И да - тело разложенное на клетки/органы/ещё что-то - это действительно другие сущности, но все они являются составляющими тело. А у вас класс финальный ;)
        Цитата wind @
        Я внимательно читал, просто это не ответ. Архитектор в принципе не может почерпнуть из учебника биологии что-либо, кроме внешнего вида и принципиального строения тела млекопитающего. Никаких интересующих вероятных пользователей деталей таким образом учтено не может быть в принципе. Кроме того, в зависимости от контекста, тело может обладать атрибутами и поведением, никак не проистекающими из учебника биологии. Если делать надстройки над данным классом, то у меня уже не получится воспользоваться какими-либо механизмами, реализованными для него. Например, если тело рассматривается как мясопродукт, то у меня не получится заставить некую машину, разделывающую тушку, заставить работать как иначе, чем заложено архитектором - он уже определил составные части, на которые следует её делить. Форменный идиотизм получается :)

        Wind, ну в самом деле. Делать класс не-финальным только из за того, что кто-то захочет с ним сотворить эдакое - грубая ошибка проектирования. На мой взгляд. Тогда давай делать все классы с виртуальными функциями, чтобы каждый желающий мог их нужным образом унаследовать и переопределить - мало ли ему чего захочется? А еще давай все данные делать открытыми. А то вдруг я вот данные закрыл, а кому-то захочется как-то с ними хитро поиграться. Как итог - полная анархия. Я к тому, что если концепция закрытая и не допускает (по логике предметной области) расширения - то никакого смысла делать ее наследуемой нет. Да. Это намеренное ограничение потенциального пользователя. Но это ограничение - вполне обоснованное. Это - желание проектировщика. Если ты с этим не согласен, ты волен выбрать любую другую библиотеку, проектировщик которой позаботился о тебе лучше, и посчитал, что пользователь захочет на базе MammalBody создать какое-нибудь UglyAlienBody добавив к нему пару дополнительных атрибутов.

        А про добавление дополнительных атрибутов - сам посуди. MammalBody с новыми атрибутами все равно получится новой сущностю. Как ты не крути. Потому что пользователи собственно MammalBody ничегошеньки об этих новых атрибутах никогда не узнают. А потому - реализуешь ли ты свое MammalSuperBody посредством наследования, или посредством агрегирования - результат получится один и тот же.
          Цитата Flex Ferrum @
          Делать класс не-финальным только из за того, что кто-то захочет с ним сотворить эдакое - грубая ошибка проектирования.

          :rolleyes:

          Цитата Flex Ferrum @
          Тогда давай делать все классы с виртуальными функциями, чтобы каждый желающий мог их нужным образом унаследовать и переопределить - мало ли ему чего захочется?

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

          Цитата Flex Ferrum @
          Я к тому, что если концепция закрытая и не допускает (по логике предметной области) расширения - то никакого смысла делать ее наследуемой нет.

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

          Например чего стоит идиотское решение разработчиков java запихнуть в абстрактный класс Preferences статические методы, systemRoot() и userRoot(). Целый фреймворк, который можно было бы использовать как front-end для любоых настроек, хранимых где угодно, летит псу под хвост.

          И далеко не всегда у пользователей есть выбор. В netbeans, например (и в eclipse, кстати), можно встретить очень много классов, объявленных финальными. Те же разработчики netbeans и eclipse создают целые механизмы обхода этой дурости на базе reflection и прочих уловок.

          Поэтому публичный финальный класс - всегда ошибка. Если нужно скрыть реализацию - пожалуйста. Запретить изменение состояния - пожалуйста. Но делать весь класс финальным - это завсегда зря.

          Цитата Flex Ferrum @
          А про добавление дополнительных атрибутов - сам посуди. MammalBody с новыми атрибутами все равно получится новой сущностю. Как ты не крути.

          Нет, вы не поняли :no: Есть класс X и целый фреймворк, завязанный на этот класс. Автор не учёл некоторых атрибутов в классе X (не нужных для функционирования его фреймворка), мне нужно их туда добавить. Да, я могу сотворить обёртку и пихать туда всё что угодно, я могу сделать какие-нибудь прокси и кастеры событий, могу наворотить целый фреймворк, интегрирующий всё вместе. Самое печальное во всём этом - у меня получится совсем другой интерфейс. Но всех этих извращений можно избежать, если я расширю этот класс наследованием.
            Цитата wind @
            В java поступают именно так - все методы виртуальные. Это много удобнее, потому что зыкрытыми для замещения будут лишь те методы, которые автор сознательно закрыл, а не все, о которых он попросту забыл.

            Ну, тут кто как поступает. Мне более логичным кажется плюсовый подход, когда автор класса сознательно (в идеале) прорабатывает интерфейс класса с возможными наследниками. Может быть для тебя это не очевидно, но это - действительно отдельный интерфейс. Более того, отдельный от публичного интерфейса. Потому что публичный интерфейс и интерфейс с наследниками выполняют совершенно разные роли. Если первый - это то, с чем будет работать внешний клиент, то второй - это своего рода, слоты расширения. Ну представь, если бы ты мог воткнуть плату любой конфигурации в любое место материнской платы. Это было бы хорошо? Сомневаюсь. Потому что само наличие такой возможности делает реализацию схемы мат. платы либо неэффективной, либо незащищенной от возможных проблем с расширителями. Почему - показывал выше. Таким образом, точки расширения класса должны быть четко определены. И эти точки расширения должны использоваться в первую очередь самим классом, как реализация полиморфизма. И это должно быть учтено на этапе проектирования. Иначе будет полный бардак.

            Цитата wind @
            Практика показывает, что таких классов, которые действительно нет смысла наследовать - практически нет в природе. Всем свойственно ошибаться, а такая ошибка дорого стоит пользователям. Кстати, в той самой природе вообще нет "финальных" сущностей.

            Ну хорошо. Наследоваться ты можешь. Но что тебе это даст, если в наследуемом классе нет виртуальных методов? :) Только простое преобразование от наследника к базе. И все, по сути. Точно такую де функцию могут выполнять обертки. А вот если тебе действительно надо расширять базу - то база должна быть спроектирована соответствующим образом.

            Цитата wind @
            Есть класс X и целый фреймворк, завязанный на этот класс. Автор не учёл некоторых атрибутов в классе X (не нужных для функционирования его фреймворка), мне нужно их туда добавить. Да, я могу сотворить обёртку и пихать туда всё что угодно, я могу сделать какие-нибудь прокси и кастеры событий, могу наворотить целый фреймворк, интегрирующий всё вместе. Самое печальное во всём этом - у меня получится совсем другой интерфейс. Но всех этих извращений можно избежать, если я расширю этот класс наследованием.

            Дело в том, что ты никак не сможешь добавить эти атрибуты в класс таким образом, чтобы фреймворк о них узнал. Увы. :)
              Цитата Flex Ferrum @
              Таким образом, точки расширения класса должны быть четко определены. И эти точки расширения должны использоваться в первую очередь самим классом, как реализация полиморфизма. И это должно быть учтено на этапе проектирования. Иначе будет полный бардак.

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

              Цитата Flex Ferrum @
              Наследоваться ты можешь. Но что тебе это даст, если в наследуемом классе нет виртуальных методов?

              Избавлюсь от ненужных обёрток, определю способы конструирования, смогу упростить клиентский код, дополню интерфейс полезными для меня функциями, не плодя всяческих helper'ов. Больше, вероятно, ничего. Отсутствие виртуальных методов для меня непривычно по понятным причинам.
                Цитата wind @
                Цитата (Flex Ferrum @ Сегодня, 12:19)
                Таким образом, точки расширения класса должны быть четко определены. И эти точки расширения должны использоваться в первую очередь самим классом, как реализация полиморфизма. И это должно быть учтено на этапе проектирования. Иначе будет полный бардак.

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

                Цитата (Flex Ferrum @ Сегодня, 12:19)
                Наследоваться ты можешь. Но что тебе это даст, если в наследуемом классе нет виртуальных методов?

                Избавлюсь от ненужных обёрток, определю способы конструирования, смогу упростить клиентский код, дополню интерфейс полезными для меня функциями, не плодя всяческих helper'ов. Больше, вероятно, ничего. Отсутствие виртуальных методов для меня непривычно по понятным причинам.

                И вот, под конец спора выясняется, что мы, на самом деле, обсуждаем не принципы ООП как такового, а отрицательный опыт Wind'а. :) Так с этого и надо было начинать: "Я имею негативный опыт работы с закрытыми иерархиями классов, по этому считаю, что ...". Тебе бы ответили, что разрабы - чудаки, нихрена не понимают в колбасных обрубках и конной авиации, и переключились бы на другую тему. :) А так - много громких слов, тезисов, возводимых в абсолют, а на самом деле вся проблема - в кривости реализации конкретных фреймворков, с которыми ты имел дело. :) Может быть для этого стоит отдельную темку на форумах java.sun.com или eclipse.org завести? :) Там обсуждение конкретных финализированных классов будет уместней. :)

                Скрытый текст
                PS: Моя практика показывает, что далеко не всегда чужое (проектное) решение, кажущееся на первый взгялд кривым, является таковым на самом деле. Нередко находится вполне разумное объяснение, почему было сделано именно так, а не иначе. В конце концов, "там" тоже не дураки сидят. :)
                  Цитата D_KEY @
                  Так что пока я не увижу реализации на делфи функционала следующих средств:
                  1) assert времени компиляции
                  2) смарт поинтер(хотя бы простенький, который удаляет память, после своего уничтожения)
                  3) распределитель памяти для маленьких объектов


                  Romkin уже все обьяснял. Попробую на примерах.

                  1.
                  Цитата D_KEY @
                  Для ассерта времени компиляции родилась задачка: Есть некая таблица(массив, задающийся на этапе компиляции, в которую периодически записываем новые элементы. Так вот, нужно ограничить ее размер. Что будете делать? Хотя есть у меня подозрения, что вы соскочите и с этой проблемки.


                  ExpandedWrap disabled
                    const
                       MAX_TABLE_SIZE = 100;
                     
                    type
                      TTable_Sizes = (0..99);
                      TTable = array[TTable_Sizes] of TElement;
                     
                    var
                      T:TTable;
                     
                    procedure InserElement(pos:TTable_Sizes;El:TElement);
                    begin
                      T[pos] := El;
                    end;
                     
                    var
                      ts:TTable_Sizes;
                      i:integer;
                    begin
                      for ts:=0 to 99 do InserElement(ts,TElement.Create);// Ok
                      ts:=-1; //assert (выход за диапазон)
                      InserElement(ts,TElement.Create);
                      ts:=100; //assert (выход за диапазон)
                      InserElement(ts,TElement.Create);
                      i:=-1;
                      ts:=i;// assert (не соответствие типов)
                      InserElement(ts,TElement.Create);
                    end.


                  2.
                  ExpandedWrap disabled
                    unit AutoObjects;
                    interface
                    type
                      IAuto_Ptr = interface
                      end;
                     
                      TAutoObjectHelper = class helper for TObject //Вариант 1
                      public
                        function _Auto: IAuto_Ptr;
                      end;
                     
                    function Auto(Obj:TObject): IAuto_Ptr;overload;                //Вариант 2
                    function Auto(var Obj;ObjCreate:TObject): IAuto_Ptr;overload;  //Вариант 3
                     
                    implementation
                    uses Dialogs,SysUtils;
                     
                    type
                      TAutoObject = class(TInterfacedObject, IAuto_Ptr)
                      private
                        FObj : TObject;
                      public
                        constructor Create(Obj:TObject);
                        destructor Destroy; override;
                      end;
                     
                    function Auto(Obj:TObject): IAuto_Ptr;
                    begin
                      Assert(Assigned(Obj));
                      Result := nil;
                      Result := TAutoObject.Create(Obj);
                    end;
                     
                    function Auto(var Obj;ObjCreate:TObject): IAuto_Ptr;
                    begin
                      Assert(Assigned(ObjCreate));
                      TObject(Obj):=ObjCreate;
                      Result := nil;
                      Result := TAutoObject.Create(ObjCreate);
                    end;
                     
                    function TAutoObjectHelper._Auto: IAuto_Ptr;
                    begin
                      Result := nil;
                      Result := TAutoObject.Create(Self);
                    end;
                     
                    constructor TAutoObject.Create(Obj:TObject);
                    begin
                      inherited Create;
                      FObj := Obj;
                    end;
                     
                    destructor TAutoObject.Destroy;
                    begin
                      ShowMessage(Format('Обьект - %s будет убит',[FObj.ClassName]));
                      FObj.Free;
                      inherited;
                    end;
                    end.


                  ExpandedWrap disabled
                    //Вариант 1
                    procedure TForm1.SomeProc_1;
                    var
                      SL:TFileStream
                    begin
                      SL:=TFileStream.Create('AutoObjects.pas',fmOpenRead);
                      SL._Auto;
                      Memo1.Lines.LoadFromStream(SL);
                    end;
                    //Вариант 2
                    procedure TForm1.SomeProc_2;
                    var
                      SL:TFileStream
                    begin
                      SL:=TFileStream.Create('AutoObjects.pas',fmOpenRead);
                      Auto(SL);
                      Memo1.Lines.LoadFromStream(SL);
                    end;
                    //Вариант 3
                    procedure TForm1.SomeProc_3;
                    var
                      SL:TFileStream
                    begin
                      Auto(SL,TFileStream.Create('AutoObjects.pas',fmOpenRead));
                      Memo1.Lines.LoadFromStream(SL);
                    end;
                    Цитата Flex Ferrum @
                    И вот, под конец спора выясняется, что мы, на самом деле, обсуждаем не принципы ООП как такового, а отрицательный опыт Wind'а.

                    Эк вы вывернули. Нет, не так. Любой объект может иметь наследников - иное не доказано. Это также проистекает из принципов ООП. Негативный опыт - это про разработчиков, которые не думают о способах расширения.

                    Цитата Flex Ferrum @
                    PS: Моя практика показывает, что далеко не всегда чужое (проектное) решение, кажущееся на первый взгялд кривым, является таковым на самом деле. Нередко находится вполне разумное объяснение, почему было сделано именно так, а не иначе. В конце концов, "там" тоже не дураки сидят.

                    Разумное объяснение обычно заключается в "лень было корячиться". Например, в java запретили создавать массивы типизированных типов, ибо лень было делать проверку в runtime. Да, эти люди начали говорить что-то о производительности - дескать, runtime-проверка при присваивании в элемент массива - зло; но они слукавили, ибо runtime-проверки для массивов (причём на любой доступ) уже существуют. Да, там сидят не дураки, но и не семи пядей во лбу обладатели, отнюдь.

                    Хотя, что касается авторов eclipse и netbeans (сужу по исходникам) - тамошние "не дураки" не только не прикасаются к коду, но даже не принимают участия в разработке модели классов. То же могу сказать о java-разработчиках ibm. Такой вот опыт.
                    Сообщение отредактировано: wind -
                      --Ins--, obj->properties задается на этапе выполнения в методе TObject::create<>, так что все будет работать и можно будет пройтись по свойствам производных классов из базового, как ты и хотел.
                      Ну что, ставишь мне(и С++) "плюсик" за задачку о проходе по свойствам производных классов из базового ;) ?

                      vlad gri, респект. Все бы так! ;)
                      Что касается задачки про ассерт времени компиляции. Или ты не так меня понял, или я не так понял твой код ;) .
                      Я говорил о следующем. Есть таблица. И есть код проверки(ассерт). Так вот,
                      на стадии компиляции я заношу элементы в табличку.
                      До какого-то момента у меня все компилится.
                      Но после добавления очередного элемента, компиляция не проходит.
                      То есть:
                      ExpandedWrap disabled
                        static const my_type my_table[] = {
                            { элемент1 },
                            { элемент2 },
                            ...
                            { элементN },
                        };
                        ...
                        //компилится только если в таблице меньше 10 элементов:
                        compile_assert<
                            sizeof( my_table ) / sizeof( my_type ) < 10
                        >;

                      Самая простая реализация compile_assert на С++ выглядит так:
                      ExpandedWrap disabled
                        template< bool exp > struct compile_assert;
                        template<> struct compile_assert<true>{};
                      Можно задавать любое логическое выражение, которое можно вычислить на этапе компиляции.

                      На счет простейшего смарт поинтера. У тебя все работает, замечательно.
                      Но как можно использовать твои объекты, которые удаляют память? Только для удаления?
                      У меня был такой код на С++:
                      ExpandedWrap disabled
                        my_class *ptr = new my_class; // обычный указатель
                        // работаем с созданным объектом через prt
                        ptr->f(); // <<< пример
                        //...
                        delete ptr;

                      Я вношу такие изменения:
                      ExpandedWrap disabled
                        auto_ptr< my_class > ptr( new my_class );
                        // работаем с созданным объектом через prt
                        ptr->f(); // <<< пример
                        //...
                        // удалять теперь не нужно

                      То есть меняю обычный указатель на auto_ptr и убираю delete.
                      На Delphi будет также?
                      Сообщение отредактировано: D_KEY -
                        Без автоматического удаления.

                        ExpandedWrap disabled
                          //Вариант 1,2,3
                          procedure TForm1.SomeProc_1_2_3;
                          var
                            SL:TFileStream
                          begin
                            SL:=TFileStream.Create('AutoObjects.pas',fmOpenRead);
                            try
                              Memo1.Lines.LoadFromStream(SL);
                            finally
                              SL.Free;  //ручками
                            end;
                          end;
                          vlad gri, о том и речь. Хотелось бы использовать такое средство как обычный указатель. В этом-то и смысл задачи.
                          Сообщение отредактировано: D_KEY -
                            Цитата D_KEY @
                            о том и речь. Хотелось бы использовать такое средство как обычный указатель. В этом-то и смысл задачи.

                            SL в обоих случаях и есть обычный указатель.
                              vlad gri, cмысл задачи: сделать средство, работающее как указатель на объект, но выполняющее некие дополнительные действия( например, может автоматически удалять память, выделенную под объект). А у тебя в обоих случаях для работы как с указателем нужно использовать именно указатель, а не разработанное тобой средство.
                              Сообщение отредактировано: D_KEY -
                                Цитата D_KEY @
                                //компилится только если в таблице меньше 10 элементов:

                                а зачем такое извращение? :huh:
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (631) « Первая ... 25 26 [27] 28 29 ...  630 631


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0857 ]   [ 15 queries used ]   [ Generated: 27.04.24, 07:44 GMT ]