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

    Ну, я и приравниваю возможность безгемморной реализации к встроенным возможностям. Второе может быть предпочтительнее, поскольку не утяжеляет язык. По-моему, korvin показывал мемоизацию функции в лиспе так, что клиенты об этом и не догадываются - ежу понятно, что одной этой возможности хватит чтобы чуть ли не полностью реализовать АОП. Но ты же понимаешь, что такая же фича в джавошарпе, не говоря уже о плюсах, равносильна бескомпромиссному горячему патчингу кода. Ну, допустим, в виртуальной машине это ещё как-то пытаются сделать, но в плюсах... здесь только в языке. Но так и языки разные, для разных вещей - ты же прекрасно понимаешь. Чёрт, где же я видел статью про горячий патч сишного кода... пошёл искать!
      Цитата Qraizer @
      D_KEY, никто не будет в один язык запихивать вообще всё, что напридумано в области дискретной математики за 60 лет.

      А об этом речи и не шло :)
      Прошу прощения, может, плохо формулирую.
        Цитата Qraizer @
        Мультиметоды реализуются без костылей

        Нормальные, со стоимостью вызова примерно равной виртуальным методам, с учётом любой иерархии наследования - неа, без костылей никак... :( И это я ещё требование не править имеющийся код не добавил...
        Цитата Qraizer @
        да и необходимость в них не так уж очевидна

        Вот мне не далее как месяц назад просто оооочень нужны были... в условиях цейтнота пришлось констрячить трёхколёсный велик на шабломакросах... очень уродский, надо сказать, велик.
          Цитата Romkin @
          Обычно на интерфейсах делают что-то вроде плагинов как раз.

          Ты забыл упомянуть "в делфи"!

          Цитата Romkin @
          Это подразумевает именно подключаемую в процессе сборки объекта конкретную реализацию ;)

          Как один из множества случаев.

          Цитата Qraizer @
          Ежели так, то и вопросов нет. Но вроде бы у них со scorpion о чём-то магическом разговор шёл. Или я не понял.

          Разговор шел о том, как юзнуть неизвестный на этапе компиляции интерфейс, который ты запросил у неизвестного на этапе компиляции объекта!
          Но потом выяснилось, что под неизвестным на этапе компиляции интерфейсом, подразумевался как раз таки известный на этапе компиляции интерфейс. Просто в понимании DesweR'а видимо под неизвестным на этапе компиляции интерфейсом, понималось именно(если исходить из твоего кода):
          ExpandedWrap disabled
            I& queryInterface(T& src)

          Буква "I" в этом всем выражении, понимаешь? А я сразу не понял его фразу: "запросить интерфейс, неизвестный на этапе компиляции, у объекта, неизвестного на этапе компиляции", поэтому и возникло у меня куча вопросов.

          Добавлено
          Вопрос не в тему
          У меня возник вопрос. Вопрос конечно, не в тему, по крайней мере не вписывается в рамки этой темы. Но я знаю что тут обитают шарписты/С++сники, которые могут помочь.
          Дело вот в чем. Есть Window Forms компонент, реализован он в виде dll, из себя представляет диалог, т.е. образно диалог, на нем RichEdit, со всякими плюшками, таб шит, кнопки OK, Cancelи т.д. . Мне все это чудо требуеца встроить в MFC фрейм, конкретно, в класс который наследуется от CView.
          Вопрос к тем кто с таким сталкивался, я могу оформить этот диалог в свою вьюшку? Как встроить Control Library написаное на .NET в вьюшку - я знаю. Реализовать в виде ActiveX, хз, думал об этом, но пока не пытался, диалог в мастер визарде, сцуко, выглядит - как диалог, со всеми кнопачками(ОК, Отмена, Закрыть, Свернуть). Вообще как быть в таком случае? Меня не интерсуют детали реализации, мне хотя бы дать толчок куда копать? ActiveX ? Встрить WinForms в Control Library и уж то что получилось в вьюшку?
          Или вообще можно реализовать так чтобы .NET диалог встроился в MFC::CView ? То, что там наследоваться нужно от WindowFormsView - это я знаю, на примере Control Library разобрался... Просто еще(даже незнаю проблема или нет?) диалог этот и все его компоненты - это по сути стороние компоненты DevExpress...
          Сообщение отредактировано: scorpion -
            Нормальные, с линейной, зависимой от количества классов в иерархии, стоимостью вызова, независящей от количества перекрытий мультиметода - релизованы Flex Ferrum-ом. Ну или где-то им подсмотренные, но это вряд ли. Там были variadic templates, сравнительно недавнее приобретение. Я её на всякий случай перенёс на C++03, заменив variadic templates на списки типов. Ну, правда там ещё есть зависимость от количества параметров мультиметода, тоже линейная, но она константная величина для фиксированной сигнатуры. Получается что-то вроде O(Σmn), где mn - глубина иерархии n-го параметра мультиметода. Это неоптимизированный код. Насколько сможет соптимизировать компилятор, судить сложно. Кроме этой реализации я видел только у Александреску, и они мне нравятся меньше. Об остальных судить не берусь.
              Qraizer, не, такая сложность меня не устраивает :(
                Счас вот проверил. 4 класса в иерархии, 2 параметра. Intel C++ compiler сделал 4 косвенных вызова, по два для каждого параметра: один - на восстановление динамического типа очередного параметера, второй - на переход к следующему параметру. Можно предположить, что по два и останется, независимо (в разумных пределах, зависящих от запаса глубины мыслей оптимизатора) от количества наследников. MSVC 2008 сделал в общем-то то же, только отдетектил два хвостовых вызова и заменил на безусловные переходы.
                  Qraizer, а реализацию посмотреть можно?
                    Меньше, чем по вызову на параметр, боюсь, не получится даже в поддержкой на уровне языка. По-любому по VMT придётся восстанавливать тип каждого параметра отдельно, и где-то хранить n-размерную матрицу указателей на перекрытые методы, а это скорее всего ещё один вызов. Так что на этом примере получилось бы три вызова.

                    Добавлено
                    Вот исходная от Flex Ferrum-а. Я её там помимо переноса под C++03 причёсывать начал, кое-где поправил, кое-что убрал, комментов понаставил, но не закончил, времени не нашёл.

                    Добавлено
                    Пока выглядит вот так:
                    ExpandedWrap disabled
                      #include <iostream>
                      #include <iomanip>
                       
                      /*******************************************************\
                      ** Списки типов, заменяющие variadic templates в C++0x **
                      \*******************************************************/
                       
                      /* Терминальный тип */
                      struct NullType {};
                       
                      /* Список типов.
                         L - голова, любой тип, кроме терминального и списка.
                         R - хвост, либо терминальный тип, либо список */
                      template <typename L, typename R> struct TList
                      {
                       typedef L Head;
                       typedef R Tail;
                      };
                       
                      /* Генератор "плоской" иерархии на основе списка типов T.
                         Все типы из списка T применяются к шаблону Node. Первый его параметр - параметризированный
                         тип из списка, второй - тип возвращаемого значения мультиметода.
                         Все получившиеся Node<T::Head> не состоят в родстве относительно друг друга, что
                         обеспечивает их равноправность при разрешении перегрузки. От базы (самого производного
                         класса GenHierarchy<>) можно однозначно добраться до любого узла путём простого кастования
                         базы к нему при условии уникальности каждого типа в списке. В нашем случае неуникальность не
                         нужна. В иных применениях поддержка таких случаев может быть несложно добавлена. */
                      template <template <typename, typename> class Node, typename Ret, typename T>
                      struct GenHierarchy;
                       
                      template <template <typename, typename> class Node, typename Ret, typename L, typename R>
                      struct GenHierarchy<Node, Ret, TList<L, R> >: public Node<L, Ret>, public GenHierarchy<Node, Ret, R>
                      {
                      };
                      template <template <typename, typename> class Node, typename Ret>
                      struct GenHierarchy<Node, Ret, NullType>
                      {
                      };
                       
                      /* Метафункция получения последнего элемента списка */
                      template <typename T>             struct Last;
                       
                      template <typename L, typename R> struct Last<TList<L, R       > >
                      {
                       typedef typename Last<R>::result result;
                      };
                      template <typename T>             struct Last<TList<T, NullType> >
                      {
                       typedef T result;
                      };
                       
                      /*******************************************************\
                      ** Наши тестовые классы и их список                    **
                      \*******************************************************/
                      class Base;
                      class D1;
                      class D2;
                      class D3;
                       
                      /* Самый базовый класс должен быть последним.
                         Впрочем, заглянув к Александреску на книжку чаю, поиск самого базового из предоставленных
                         можно автоматизировать. Я не стал копить сюда лишнего метакода. */
                      //typedef TList<D3, TList<D2, TList<D1, TList<Base, NullType> > > > Hierarchy;
                      typedef TList<D2, TList<D1, TList<D3, TList<Base, NullType> > > > Hierarchy;
                       
                      /********************************************************************************\
                      *****************      Далее следует реализация мультиметодов     ****************
                      \********************************************************************************/
                       
                      /* Узел "плоской" иерархии */
                      template <typename T, typename Ret> class AcceptorBase
                      {
                      public:
                         virtual Ret Accept(T* obj) = 0;
                      };
                       
                      /* Генератор узлов "плоской" иерархии.
                         Первый параметр - исходный список, второй - тип возвращаемого значения мультиметода */
                      template <typename TL, typename Ret> class Acceptor: public GenHierarchy<AcceptorBase, Ret, TL>
                      {
                      public:
                         typedef TL TypeList;
                       
                         /* Создаёт метафункцию type, конкретизирущую в построенной иерархии метафункцию двух
                            параметров-типов GA типом B */
                         template <typename B, template <typename, typename> class GA> struct MakeAcceptor
                         {
                             typedef GA<B, TL> type;
                         };
                      };
                       
                      /* Создаём "плоскую" иерархию по нашему списку */
                      typedef Acceptor<Hierarchy, void> ConcreteAcceptor;
                       
                      /* Определяем несколько мультиметодов */
                      void TestDispatch(Base* b1, Base* b2)
                      {
                         std::cout << "Double Base-Base Dispatch" << std::endl;
                      }
                       
                      void TestDispatch(D1* o1, Base* o2)
                      {
                         std::cout << "Double D1-Base   Dispatch" << std::endl;
                      }
                       
                      void TestDispatch(D1* o1, D2* o2)
                      {
                         std::cout << "Double D1-D2     Dispatch" << std::endl;
                      }
                       
                      void TestDispatch(D2* o1, D3* o2)
                      {
                         std::cout << "Double D2-D3     Dispatch" << std::endl;
                      }
                       
                      void TestDispatch(D3* o1, D2* o2)
                      {
                         std::cout << "Double D3-D2     Dispatch" << std::endl;
                      }
                       
                      void TestDispatch(D3* o1, D3* o2)
                      {
                         std::cout << "Double D3-D3     Dispatch" << std::endl;
                      }
                       
                      /********************************************************************************\
                      *****************               Обобщённый диспетчер              ****************
                      \********************************************************************************/
                       
                      /* Параметр - конкретный диспетчер. Должен:
                         предоставлять тип ret_type являющийся типом возвращаемого значения мультиметода;
                         иметь перегруженный operator(), принимающий любую по меньшей мере определеяемую набором
                           имеющихся мультиметодов комбинацию параметров из списка типов и возвращающий ret_type;
                         уметь конструироваться bool-ом (в общем-то требование избыточное, сейчас используется
                           в исследовательских целях) и использовать его для реверса порядка параметров;
                         в ответ на вызов его operator() вызывать собственно мультиметоды с тем же набором
                           паметров. */
                      template <typename DI>
                      struct Dispatcher
                      {
                         typedef typename DI::ret_type ret_type;      // Тип возвращаемого значения к себе
                       
                         /* Акцепторы левого и правого параметров. Сейчас совпадают, ибо предполагается, что
                            параметры мультиметода симметричны. В целом же это необязательно */
                         template <typename B, typename TL> struct LeftAcceptorCaller;
                         template <typename B, typename TL> struct RightAcceptorCaller;
                       
                         template <typename L>
                         struct AcceptorMaker
                         {
                             typedef typename ConcreteAcceptor::MakeAcceptor<ret_type, LeftAcceptorCaller >::type left_type;
                             typedef typename ConcreteAcceptor::MakeAcceptor<L,        RightAcceptorCaller>::type right_type;
                         };
                       
                         template <typename L, typename T, typename R>
                         struct RightAcceptorCaller<L, TList<T, R> > : public RightAcceptorCaller<L, R>
                         {
                             typedef RightAcceptorCaller<L, TList<T, R> > this_type;
                             typedef RightAcceptorCaller<L,          R  > base_type;
                       
                             RightAcceptorCaller(L* l, DI* di) : base_type(l, di) {}
                       
                             ret_type Accept(T* obj)
                             {
                                 return base_type::m_DispImpl->operator()(base_type::m_Left, obj);
                             }
                         };
                       
                         template <typename L, typename R>
                         struct RightAcceptorCaller<L, TList<R, NullType> > : public ConcreteAcceptor
                         {
                             typedef RightAcceptorCaller<L, TList<R, NullType> > this_type;
                       
                             RightAcceptorCaller(L* l, DI* di) : m_Left(l), m_DispImpl(di) {}
                       
                             ret_type Accept(R* obj)
                             {
                                 return m_DispImpl->operator()(m_Left, obj);
                             }
                       
                             L  *m_Left;
                             DI *m_DispImpl;
                         };
                       
                         template <typename T>
                         struct LeftAcceptorCaller<ret_type, TList<T, NullType> > : public ConcreteAcceptor
                         {
                             typedef LeftAcceptorCaller<ret_type, TList<T, NullType> > this_type;
                       
                             LeftAcceptorCaller(T* r, DI* di) : m_Right(r), m_DispImpl(di) {}
                       
                             ret_type Accept(T* obj)
                             {
                                 typedef typename AcceptorMaker<T>::right_type acceptor;
                       
                                 acceptor a(obj, m_DispImpl);
                                
                                 return m_Right->Accept(a);
                             }
                       
                             T  *m_Right;
                             DI *m_DispImpl;
                         };
                       
                         template <typename L, typename R>
                         struct LeftAcceptorCaller<ret_type, TList<L, R> > : public LeftAcceptorCaller<ret_type, R>
                         {
                             typedef LeftAcceptorCaller<ret_type, TList<L, R> > this_type;
                             typedef LeftAcceptorCaller<ret_type,          R  > base_type;
                             typedef typename Last<R>::result              most_base_type;
                       
                             LeftAcceptorCaller(most_base_type* r, DI* di) : base_type(r, di) {}
                       
                             ret_type Accept(L* obj)
                             {
                                 typedef typename AcceptorMaker<L>::right_type acceptor;
                                
                                 acceptor a(obj, base_type::m_DispImpl);
                                
                                 return base_type::m_Right->Accept(a);
                             }
                         };
                       
                         ret_type operator ()(typename AcceptorMaker<ret_type>::left_type::this_type::most_base_type* l,
                                              typename AcceptorMaker<ret_type>::left_type::this_type::most_base_type* r)
                         {
                             typedef typename AcceptorMaker<ret_type>::left_type acceptor;
                       
                             DI       di;
                             acceptor a(r, &di);
                       
                             return l->Accept(a);
                         }
                      };
                       
                      template <typename T = void>
                      class TestDispatcher
                      {
                      public:
                         typedef T ret_type;
                       
                         template <typename L, typename R>
                         T operator()(L* l, R* r)
                         {
                             return TestDispatch(l, r);
                         }
                       
                         template <typename L, typename R>
                         T TestDispatch(L* l, R* r)
                         {
                             return ::TestDispatch(l, r);
                         }
                      };
                       
                      /* Макро для удобства */
                      #define MAKE_ACCEPTABLE(A, C) virtual void Accept(A& a)                                        \
                                                    {                                                                \
                                                     return static_cast<AcceptorBase<C, void>*>(&a)->Accept(this);   \
                                                    }
                       
                      class Base
                      {
                      public:
                         MAKE_ACCEPTABLE(ConcreteAcceptor, Base);
                      };
                       
                      class D1 : public Base
                      {
                      public:
                         MAKE_ACCEPTABLE(ConcreteAcceptor, D1);
                      };
                       
                      class D2 : public D1
                      {
                      public:
                         MAKE_ACCEPTABLE(ConcreteAcceptor, D2);
                      };
                       
                      class D3 : public Base
                      {
                      public:
                         MAKE_ACCEPTABLE(ConcreteAcceptor, D3);
                      };
                       
                      int main()
                      {
                         Base b;
                         D1   d1;
                         D2   d2;
                         D3   d3;
                       
                         std::cout << std::boolalpha;
                         {
                            Dispatcher<TestDispatcher<> > d;
                       
                            d(&b , &b );
                            d(&b , &d1);
                            d(&b , &d2);
                            d(&b , &d3);
                       
                            std::cout << std::endl;
                       
                            d(&d1, &b );
                            d(&d1, &d1);
                            d(&d1, &d2);
                            d(&d1, &d3);
                       
                            std::cout << std::endl;
                       
                            d(&d2, &b );
                            d(&d2, &d1);
                            d(&d2, &d2);
                            d(&d2, &d3);
                       
                            std::cout << std::endl;
                       
                            d(&d3, &b );
                            d(&d3, &d1);
                            d(&d3, &d2);
                            d(&d3, &d3);
                         }
                         std::cout << std::endl;
                         return 0;
                      }


                    Добавлено
                    Вообще, хотелось в ним поболтать на кое-какие темы и родить нормальную библиотечную версию. Он даже не был против, но рутина затянула. Программа максимум - параметризировать количество параметров мультиметода.
                      Qraizer, благодарю.
                      Цитата Qraizer @
                      Меньше, чем по вызову на параметр, боюсь, не получится даже в поддержкой на уровне языка.

                      Ну, вот у мужиков ведь получилось :)
                      Цитата
                      In particular, the runtime cost of calling an open multimethod is constant and less than the cost of a double dispatch (two virtual function calls). Finally, we provide a sketch of a design for open multi-methods in the presence of dynamic loading and linking of libraries.
                      Сообщение отредактировано: MyNameIsIgor -
                        Напомните плз, про мультиметоды, только в вики не посылайте плз, а то там непонятно както :huh:
                          scorpion, как я понял, он неконкретно выразился. Под неизвестным заранее он подразумевал неизвестным не на момент компиляции, а на момент написания. С шаблонами у нас та же картина - когда мы пишем шаблонный код, мы не знаем параметров шаблона, но они известны в точках использования, т.е. на момент компиляции аргументам обязательно что-то сопоставлено. Лучше пусть сам уточнит.
                          D_KEY, ну... сорри тогда. Я воспринял так, что ты предъявляешь это всё как большой недостаток.
                            Цитата Qraizer @
                            Под неизвестным заранее он подразумевал неизвестным не на момент компиляции, а на момент написания.

                            Да, это я понял уже. Я уже и намекал ему на шаблоны, в том и дело, что запутал он меня просто.
                              Цитата scorpion @
                              Цитата DesweR @
                              Всё правильно, реализуются явно указанные интерфейсы, такова идеология COM.
                              Пол года назад уже был разговор:

                              Ну и там же явно сказано:
                              Цитата DesweR @
                              Тоже самое касается и наследования интерфейсов, должен соблюдаться не только сигнатурный контракт, но и гарантированно семантический, а для этого класс A, должен содержать реализацию интерфейсов и child и parent.

                              Так понятней?
                              Цитата DesweR @
                              Тоже самое касается и наследования интерфейсов, должен соблюдаться не только сигнатурный контракт, но и гарантированно семантический, а для этого класс TBC1, должен содержать реализацию интерфейсов и IB, IC и IA.

                              ExpandedWrap disabled
                                  IA = Interface
                                    procedure Foo;
                                  end;
                                 
                                  IB = Interface(IA)
                                    //***//
                                  end;
                                 
                                  IC = Interface(IA)
                                    //***//
                                  end;
                                 
                                  TBC1 = class(TInterfacedObject, IB, IC)
                                  private
                                    procedure Foo;
                                  end;

                              т.е.
                              ExpandedWrap disabled
                                  TBC1 = class(TInterfacedObject, IA, IB, IC)
                                  private
                                    procedure Foo;
                                  end;


                              Цитата MyNameIsIgor @
                              Цитата DesweR @
                              В таком случае все варианты, когда реализация должна быть скрыта в классе, идут лесом. Оно вообще тогда надо?

                              Не понял...

                              Я имею ввиду случаи, когда реализации интерфейсов скрываются либо в целях ограничения доступа извне, либо из-за удобства декомпозиции самого функционала.
                              ExpandedWrap disabled
                                  IGuest = interface
                                    procedure ReadDocument;
                                  end;
                                 
                                  IUser = interface(IGuest)
                                    procedure WriteDocument;
                                  end;
                                 
                                  IAdmin = interface(IUser)
                                    procedure CreateDocument;
                                    procedure DeleteDocument;
                                  end;
                                 
                                  TMailService = class(TInterfacedObject, IGuest, IUser, IAdmin)
                                  private
                                    procedure ReadDocument;
                                    procedure WriteDocument;
                                    procedure CreateDocument;
                                    procedure DeleteDocument;
                                  end;
                                 
                                 
                                  ILogger = interface
                                    procedure SendMessage;
                                  end;
                                 
                                  ILog = interface
                                    procedure ReadMessages;
                                  end;
                                 
                                  IConfig = interface
                                    procedure FormatFile;
                                    procedure OutputDirectory;
                                    procedure MessageFilter;
                                  end;
                                 
                                  TLogService = class(TInterfacedObject, ILogger, ILog, IConfig)
                                  private
                                    procedure SendMessage;
                                    procedure ReadMessages;
                                    procedure FormatFile;
                                    procedure OutputDirectory;
                                    procedure MessageFilter;
                                  end;

                              Но. И в любых других случаях, также нет смысла делать реализацию публичной, без какой-либо необходимости на то, т.к. клиенты всё равно работают через интерфейсы, а не через реализующие их объекты.

                              Цитата Qraizer @
                              scorpion, как я понял, он неконкретно выразился. Под неизвестным заранее он подразумевал неизвестным не на момент компиляции, а на момент написания.

                              Параметрический метод ввёл вас слегка в заблуждение.
                              ExpandedWrap disabled
                                procedure Reg<T>;

                              так
                              ExpandedWrap disabled
                                procedure Reg();

                              Нет, я действительно имел ввиду неизвестный на момент компиляции.
                              Либо пользователем из gui, либо каким-нибудь алгоритмом, по заданным условиям, определяются доступные реализации и регистрируются в фабрике.
                              ExpandedWrap disabled
                                  for i := 0 to List.Count - 1 do
                                    Factory.Reg(List[i]);


                              Цитата Qraizer @
                              DesweR, это подправление здорово изменило отношения классов. Это ли не редизайн? Интересно будет послушать твоего коллегу, который после такой небольшой подправки получит у себя поведение, описываемое Flex Ferrum-ом.

                              Эм... но ты сам это просил.
                              Хорошо, а что тебя будет ждать, если это повторить на абстрактных классах?
                              Сообщение отредактировано: DesweR -
                                Цитата D_KEY @
                                поддержки аспектно-ориентированного программирования, ... Есть не очень успешные попытки это делать, как раз на страшных костылях...

                                АОП -- разве все три реализации плохи? (я-то их сам не видел)
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (495) « Первая ... 312 313 [314] 315 316 ...  494 495


                                Рейтинг@Mail.ru
                                [ Script execution time: 0.4435 ]   [ 15 queries used ]   [ Generated: 31.07.26, 21:47 GMT ]