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

      Метод требует, чтобы все поля класса были сконструированы, делегирующий конструктор - нет.

      После отработки вызываемого конструктора у тебя будет готовый объект со всеми инициализированными полями. Или я ошибаюсь и тут?
        Цитата D_KEY @
        После отработки вызываемого конструктора у тебя будет готовый объект со всеми инициализированными полями. Или я ошибаюсь и тут?

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

        Добавлено
        Цитата D_KEY @
        Виртуальные методы вводят новую концепцию динамической диспетчеризации метода по типу объекта.

        Что на практике всего лишь указатели на функции - можно сделать руками.
          Цитата MyNameIsIgor @
          делегирующий же конструктор именно частью списка инициализации и является.

          Так ведь чисто синтаксически. Объект-то полностью проинициализирован будет после его вызова.
            Цитата D_KEY @
            Так ведь чисто синтаксически. Объект-то полностью проинициализирован будет после его вызова.

            Так в том то и дело, что после. Потому и нельзя заменить на метод, т.к. тогда у нас объект частично должен быть сконструирован до вызова.

            Добавлено
            D_KEY, вот код
            ExpandedWrap disabled
              struct test
              {
                  int& i;
                  std::string s;
                  test(int& i) : test(i, std::string()) {}
                  test(int& i, std::string s) : i(i), s(std::move(s)) {}
              };

            Замени на метод.
              Цитата MyNameIsIgor @
              Цитата Qraizer @
              делегирующий конструктор - метод

              Метод требует, чтобы все поля класса были сконструированы, делегирующий конструктор - нет.
              Отнюдь. Метод не обязан полагаться на контракты. Да, это плохо, но в каждом классе есть хотя бы один такой, собственно конструктор (иногда неявный), так что считать ли некий метод (не конструктор) специальным, личное дело прогаммера. Впрочем, на эту тему я писал не раз, не буду повторяться. Там один итог в итоге: такие методы должны быть приватные. Собственно делегируемые конструкторы по ряду причин тоже.
              Цитата MyNameIsIgor @
              Цитата Qraizer @
              пользовательские литералы- #defines

              Я подумаю... Не очень хорошо знаю пользовательские литералы. Но как минимум - засорение глобального пространства имён.
              Т.е. таки сахар. Вместо макросов подойдут и inline. Даже constexpr, если есть возможность.
              Цитата MyNameIsIgor @
              Цитата Qraizer @
              override - улучшенная диагностика многих компиляторов

              Полагаться на это можно, но потребовать её какими бы то ни было методами вы не можете. Следовательно, это новая функциональность, а не сокращённая запись старой.
              Не новая, улучшенная старая, которую многие компиляторы и так предоставляли, так что теперь она стандартизирована.
              Цитата MyNameIsIgor @
              Цитата Qraizer @
              noexcept - throw();

              Нет. Я могу написать
              ExpandedWrap disabled
                template<class T>
                void foo(T t) noexcept(noexcept(T(t)) { /*...*/ }

              И вообще, noexept(expression) - это константное выражение, которое я могу использовать, например, при выборе специализации шаблона.
              Это прекрасно делалось мааааленькой модификацией семантики throw-спецификаторов.
              Но тут надо отметить, что throw()-спецификаторы себя не оправдали. Так что на лицо не столько сахар, сколько мотивация к отказу от старой семантики.
              Цитата MyNameIsIgor @
              Цитата Qraizer @
              std::nested_exception - не заменяется, но непонятно, а занафик нужно, окромя редчайших моментов отладки

              Нужно, чтобы донести до обработчика первичное исключение, если оно пролетает через несколько слоёв архитектуры, и залогировать его, чтобы знать первопричину.
              Вот и я об этом. Коли исключение произошло, его требуется донести. Зачем к чему тогда ещё одно новое? Только ради замены. Тогда зачем доносить исходное, если архитектурно оно должно быть заменено?
              В общем, я не вижу места этой фиче в продакшне. Но я оговорился, что тут могу ошибаться.

              Добавлено
              Цитата D_KEY @
              Так ведь чисто синтаксически. Объект-то полностью проинициализирован будет после его вызова.
              Ум-м-м... до меня только что дошло. После отработки делегируемого объект-то уже будет иметь свой собственный динамический тип, ведь так? Так что не виртуальные конструкторы, "о котором так много говорили ©" дельфисты, но-таки полноформатный полиморфизм в делегирующем конструкторе мы вполне получаем. Однако, во-первых, нет симметрии с деструкторами, во-вторых, ... ну были ж фабрики.
                Цитата Qraizer @
                Отнюдь.

                Ну, тогда измените мой пример.
                Цитата Qraizer @
                Т.е. таки сахар

                Я же сказал - надо подумать.
                Цитата Qraizer @
                Не новая, улучшенная старая

                Т.е. вы таки покажете код, который гарантированно на любом компиляторе покажет мне требуемую диагностику?
                Цитата Qraizer @
                Это прекрасно делалось мааааленькой модификацией семантики throw-спецификаторов.

                Т.е. не сахар.
                Цитата Qraizer @
                Вот и я об этом. Коли исключение произошло, его требуется донести. Зачем к ему ещё одно новое? Только ради замены. Тогда зачем доносить исходное, если архитектурно оно должно быть заменено?
                В общем, я не вижу места этой фиче в продакшне. Но я оговорился, что тут могу ошибаться.

                Оставив в стороне необходимость фичи, я не понимаю, каким образом она является синтаксическим сахаром?

                Добавлено
                Цитата Qraizer @
                После отработки делегируемого объект-то уже будет иметь свой собственный динамический тип, ведь так?

                С чего бы? Конструктор потомка то ещё не отработал.
                  Цитата MyNameIsIgor @
                  Ну, тогда измените мой пример.
                  Зачем? Ты понял мою мысль, я понял твою. Я ж не говорю, мол, бесполезная фича, я говорю, без неё обойтись можно практически безболезненно. Для сравнения: без лямбд тоже обойтись можно, но отнюдь не так безболезненно.
                  Цитата MyNameIsIgor @
                  Т.е. вы таки покажете код, который гарантированно на любом компиляторе покажет мне требуемую диагностику?
                  Если б он был, не требовалось бы ничего нового стандартизировать. Фактически же, разница примерно как с неявным int-ом: в C это варнинг, в C++ - ошибка.

                  P.S. Когда занимался мультиметодами, интеловый компилер достал просто этим варнингом. Но там так было нужно, это не ошибка. Получалось что-то вроде (после разворачивания списков типов):
                  ExpandedWrap disabled
                    template <typename T> class Value { virtual T doIt() = 0; };
                     
                    template <typename T1, typename T2>
                    class A: public Value<T1>, public Value<T2> { /* ... */ };
                     
                    template <typename T1, typename T2>
                    class B1: public A<T1, T2> { virtual T1 doIt(); };
                     
                    template <typename T1, typename T2>
                    class B2: public B1<T1, T2> { virtual T2 doIt(); };
                  Класс A использовался для восстановления динамического типа Tx из базового T посредством вызова селектора Value<>::doIt(). Список типов из вот таких вот A итерировался по всем параметрам мультиметода, восстанавливая динамический тип каждого.

                  Добавлено
                  Цитата MyNameIsIgor @
                  Оставив в стороне необходимость фичи, я не понимаю, каким образом она является синтаксическим сахаром?
                  Ну не синтаксическим. Всё равно сахаром. Разве сложно это сделать самостоятельно? При определённых условиях. Я ради прикола когда-то реализовал подобную вещь на BC4.5 ещё, который в отличие от VC и Intel поддерживал спецификацию исключений для функций, и использовал её, чтобы протащить неожидаемое исключение сквозь спецификацию наружу. При условии единого полиморфного предка для всех классов исключений с фабрикой копирования контейнер сооружается легко. Вот только не пригодилось ни разу. Вся роль нового Стандарта тут, это обязывание компиляторов делиться скрытой RTTI с реализациями STL, чтобы те могли предоставить готовый же std::nested_exception без упомянутых ограничений.

                  Добавлено
                  Цитата MyNameIsIgor @
                  С чего бы? Конструктор потомка то ещё не отработал.
                  Но отработал конструктор конструируемого класса. И пусть делегируемый, а делегирующий ещё нет, деструктор-то вызовется, ежели чё.
                  Цитата MyNameIsIgor @
                  Замени на метод.
                  Не уловил сути задачи. Что мешает написать просто test(int& i) : i(i) {};?

                  Добавлено
                  Чёрт... Парни, подскажите, где лучше всего создать тему по мультиметодам. В январе пойду в отпуск на пару недель, надо взять себя в руки и-таки опубликовать. Лучше всего подходят "Наши проекты", но я там редкий гость. Плюсовый раздел подходит для обсуждения, но не публикации.
                  Сообщение отредактировано: Qraizer -
                    Цитата Qraizer @
                    но я там редкий гость

                    Ну и что, что редкий? Там и публикуй.
                      Та я ж забуду туда заглядывать.

                      Добавлено
                      А! Подписка ж есть. Да, похоже ты прав.

                      Добавлено
                      О! А обсуждение можно и Плюсовом разделе оформить. Точно.
                        Дельфисты, поясните, плз, что тут не так:
                        ExpandedWrap disabled
                          type
                            IMyInterface = interface                ['некий GUID']
                              procedure Handle;
                            end;
                           
                            IMyInterface2 = interface(IMyInterface) ['некий другой GUID']
                            end;
                           
                            TMyObject = class(TInterfacedObject, IMyInterface, IMyInterface2) // E2291: Missing implementation of interface method IMyInterface.Handle.
                            protected
                              procedure _Handle;
                              procedure IMyInterface.Handle = _Handle;
                            end;
                           
                          procedure TMyObject._Handle;
                          begin
                          end;
                        С моим пониманием интерфейсов всё должно быть в порядке. Даже на Плюсах проверил:
                        ExpandedWrap disabled
                          class IMyInterface
                          {
                          public:
                            virtual void Handle() = 0;
                          };
                           
                          class IMyInterface2: public IMyInterface
                          {
                          };
                           
                          class TMyObject: virtual public IMyInterface, virtual public IMyInterface2
                          {
                          protected:
                            void _Handle() {}
                            void Handle() { _Handle(); }
                          };
                           
                          TMyObject a;
                        Или я чего-то не так понимаю в интерфейсах?

                        Добавлено
                        P.S. Правильно ли я понимаю, что причина в разных GUID, из-за чего IMyInterface.Handle и IMyInterface2.Handle тоже разные, и если б GUID не различались (это вообще возможно?), то и проблемы б не было?
                          неверное имя в сообщении, похоже баг

                          Цитата Qraizer @
                          Дельфисты, поясните, плз, что тут не так:

                          класс обязан выполнить два контракта:

                          1. автопилот(сопоставление по имени)
                          ExpandedWrap disabled
                            TMyObject = class(TInterfacedObject, IMyInterface, IMyInterface2)
                              protected
                                procedure Handle;
                              end;


                          а) метод Handle в классе есть - контракт IMyInterface выполнен
                          б) метод Handle в классе есть - контракт IMyInterface2 выполнен
                          ок

                          2. ручное управление
                          ExpandedWrap disabled
                            TMyObject = class(TInterfacedObject, IMyInterface, IMyInterface2)
                              protected
                                procedure _Handle;
                                procedure IMyInterface.Handle = _Handle;
                              end;

                          а) контракт IMyInterface выполняется с помощью метода _Handle
                          б) метод Handle отсутствует - - контракт IMyInterface2 НЕ выполнен
                          фейл

                          Цитата Qraizer @
                          Даже на Плюсах проверил:

                          шикарно :lool:

                          ExpandedWrap disabled
                            type
                              IMyInterface = interface
                                procedure Handle;
                              end;
                             
                              IMyInterface2 = interface(IMyInterface)
                              end;
                             
                              TMyObject = class(TInterfacedObject, IMyInterface, IMyInterface2)
                              public
                                procedure _Handle;
                                procedure Handle;
                              end;
                             
                            procedure TMyObject._Handle;
                            begin
                            end;
                             
                            procedure TMyObject.Handle;
                            begin
                              _Handle;
                            end;

                          тоже работает :lol:

                          PS с т.з. языка IMyInterface, IMyInterface2 - это два разных типа
                          это не зависит от наличия и значения GUID'а

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

                          ExpandedWrap disabled
                            type
                              IMyInterface = interface ['GUID']
                                procedure Handle; safecall;
                              end;
                             
                              IMyInterface2 = interface ['GUID']
                                function Handle:HRESULT; stdcall;
                              end;
                             
                              TMyObject = class(TInterfacedObject, IMyInterface)
                              public
                                procedure Handle;
                              end;
                             
                              ...
                             
                              Intf:=Obj as IMyInterface; // и далее работаем с исп. исключений
                              Intf:=Obj as IMyInterface2; // исп. коды ошибок
                            Вот в этом-то и был вопрос: если IMyInterface2 расширяет IMyInterface, то IMyInterface.Handle в равной мере принадлежит обоим интерфейсам. Т.е. прикол в том, что ручная делегация не затрагивает IMyInterface2, и это не ошибка модели интерфейсов в языке, а тупо нефик лезть руками в вещи, которые легко сломать, если не понимаешь, что делаешь?

                            Добавлено
                            Цитата Shaggy @
                            PS с т.з. языка IMyInterface, IMyInterface2 - это два разных типа
                            это не зависит от наличия и значения GUID'а
                            Ну это-то понятно. Другое дело, что один из них является подтипом другого и в этом смысле полностью заменяем им, но не наоборот (что, впрочем, при пустом IMyInterface2 не имеет значения).

                            Добавлено
                            Тогда дополнительно ещё три вопроса:
                            1. Почему ручная делегация не затрагивает унаследованный от базового интерфейса метод расширяющего интерфейса? Тут припоминается кипели баталии касательно того, что интерфейсы просто нужно реализовать где-нибудь, и пофик, как они там сводятся в реализации, и что, мол, у абстрактных классов такой фигни тем, поэтому фэйл. А на поверку выходит, что один и тот же интерфейс IMyInterface, будучи в TMyObject доступным по двум маршрутам, в Плюсах как и положено отлично сливается в одну копию, а в Дельфях присутствует в двух экземплярах, и только усилиями самого компилятора этого не заметно, до поры до времени.
                            2. Не является ли это свидетельством того, что модель абстрактных классов всё-таки более обща, поэтому, пусть и с акцентом наоборот, но Дельфи, как и Плюсы, позволяют при необходимости не сливать несколько одинаковых интерфейсов в одну копию?
                            3. Почему в ошибке фигурирует IMyInterface, который реализован, вместо IMyInterface2, посредством которого IMyInterface доступен вторым маршрутом? Вообще, какие там маршруты получаются в итоге: IMyInterface2.IMyInterface.Handle и IMyInterface.Handle? Или же вместо первого всё-таки просто IMyInterface2.Handle?
                            Я не придираюсь, я хочу разобраться. На последний вопрос и в контексте Плюсов не так-то просто ответить.

                            Добавлено
                            Цитата Shaggy @
                            это конечно чревато, но иногда удобно
                            ...
                            Хм... а это, случайно, не грязный хак? safecall кем обеспечивается? Разве не самим методом?
                            Сообщение отредактировано: Qraizer -
                              от интерфейса не наследуются, его реализуют(как и получают) целиком, как неделимую единицу
                              поэтому в записи:
                              ExpandedWrap disabled
                                TMyObject = class(TInterfacedObject, IMyInterface, IMyInterface2)

                              IMyInterface реализуется один раз и доступен по одному маршруту
                              в Interface table этого класса всего три записи: IInterface, IMyInterface, IMyInterface2

                              а из этого класса:
                              ExpandedWrap disabled
                                TMyObject2 = class(TObject, IMyInterface2)

                              мы не сможем получить даже IInterface т.к.
                              в Interface table этого класса одна запись: IMyInterface2

                              но:
                              ExpandedWrap disabled
                                var
                                  Obj:TMyObject2;
                                  Intf:IMyInterface2
                                  I:IInterface;
                                begin
                                  ...
                                  Intf:=Obj as IMyInterface2; // получение интерфейса
                                  // или
                                  Intf:=Obj; // неявный as
                                  ..
                                  I:=Obj; // неявный as, но облом, не реализован IInterface
                                  I:=Intf; // тут, т.к. IMyInterface наследуется от IInterface, просто усечение


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

                              с сообщением похоже просто баг, я уже отправил репорт

                              Цитата Qraizer @
                              а это, случайно, не грязный хак?

                              ну как сказать...

                              например, в самой IDE есть галочка - импортировать интерфейсы из TLB c safecall или stdcall методами
                              Цитата
                              Safecall functions automatically implement COM conventions for errors and exception handling, converting HRESULT error codes into exceptions. If you are entering function declarations in RIDL, you must explicitly specify the calling convention as safecall or stdcall.


                              Добавлено
                              и да, правильнее всё-таки говорить о расширении интерфейсов, а не о наследовании
                              т.к. при такой записи (если бы она была разрешена)
                              ExpandedWrap disabled
                                type
                                  IMyIntf3 = interface(IMyIntf, IMyIntf2)

                              мы бы поимели ваши проблемы: дублирование _AddRef, _Release, QyeryInterface
                              (и это только в самом простом случае)
                                Ну, как бы как я себе и представлял.
                                Цитата Shaggy @
                                с сообщением похоже просто баг, я уже отправил репорт
                                Ага. Вот теперь у меня всё срослось. Вроде.
                                Тогда в заключение: расширение интерфейса и его наследование в вашей терминологии – в чём разница? Я понимаю так, что расширение – это создание нового на основе существующего, при этом новый включает в себя из него всё. Наследование интерфейса как термин по-хорошему вообще не используется, и вместо него существует термин "реализация интерфейса". Получается, что нельзя создать новый интерфейс, расширив более одного?

                                Добавлено
                                Цитата Shaggy @
                                например, в самой IDE есть галочка - импортировать интерфейсы из TLB c safecall или stdcall методами
                                Цитата
                                Safecall functions automatically implement COM conventions for errors and exception handling, converting HRESULT error codes into exceptions. If you are entering function declarations in RIDL, you must explicitly specify the calling convention as safecall or stdcall.
                                А, т.е. компилятор для safecall фактически создаёт некий прокси над тем, что написал програмер. О как.
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (495) « Первая ... 492 493 [494] 495 


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,4140 ]   [ 16 queries used ]   [ Generated: 28.03.24, 19:31 GMT ]