На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
> type ::* , Непонятная конструкция
    Добрый день.

    Попалась в справочном материале непонятная мне конструкция. Компилируется, но что это и как такое может быть не понимаю.

    ExpandedWrap disabled
      struct S
      {
      int data;
      S():data(33){}
      };
       
       
       int S::* f;  // ??????

    поисковики выпинывают на указатели, но f не указатель. что это?
      Указатель на элемент класса S типа int.

      Добавлено
      ExpandedWrap disabled
        f = &S::data;
         
        S x, y, *z = new S;
        /* ... */
         
        x.*f = y.*f + z->*f;
         
        /* ... */
        delete z;


      Добавлено
      В целом указатели на данные класса просто замещают тобой макрос offsetof() из C, при этом делая операции типобезопасными и более удобными. Но чаще встречаются указатели на методы класса, и они куда более мощная штука. Особенно если вспомнить, что методы бывают виртуальными, а классы виртуально наследуемыми.

      P.S. И да, они не указатели в том смысле, что не совместимы с простыми указателями на данные или функции. Даже с void*. И даже с указателями на такие же элементы другого класса, если только эти классы не связаны единой иерархией наследования. И над ними нет адресной арифметики. И sizeof() от них бывает довольно странный.
      Сообщение отредактировано: Qraizer -
        Интересная конструкция, тоже никогда не встречал ее упоминаине
        Цитата Qraizer @
        В целом указатели на данные класса просто замещают тобой макрос offsetof() из C, при этом делая операции типобезопасными и более удобными.

        Где про это можно почитать? У меня есть код с offsetof и этот код мне не нравится:
        Скрытый текст

        ExpandedWrap disabled
              struct address_map
              {
                  data        Data;
                  uint8_t     Temperature;        // -75...125 deg.C, ~0.8 deg.C/LSB
                  uint8_t     TU              :  2;   // time unit of the synchronization events. Only 2 bits are used,
                                                      // and the corresponding time units are 2^(-11), 2^(-12), 2^(-13),
                                                      // and 2^(-14) of the TPH, respectively, for the TU value of 00, 01, 10, and 11.
                                                      // Alternatively, this byte can be defined by I3C CCC command, with the defining
                                                      // byte of 0x9F, followed by one byte of data.
                  uint8_t     reserved1[11];
                  status      Status;
                  uint8_t     ODR;                    // This byte defines the frequency of the continuous-mode measurements. ODR can
                                                      // be defined by either writing the number into this register, or using SETXTIME
                                                      // CCC command, followed by defining byte of 0x8F. In order to enter the continuous
                                                      // mode, this byte should not be zero. The configurable ODR is 1 to 255, with
                                                      // increment of 1. The 1000 Hz ODR is available by writing 255 into this byte and
                                                      // setting hpower to 1
           
                  struct control
                  {
                      core::control::reg0     Reg0;
                      core::control::reg1     Reg1;
                      core::control::reg2     Reg2;
                  }           Control;
           
                  uint8_t     Selftest_threshold[MAX_AXIS];
           
                  uint8_t     reserved2[6];
                  uint8_t     Selftest_set_signal[MAX_AXIS];
           
                  uint8_t     reserved3[15];
                  uint8_t     Product_ID;
              } __attribute__((__packed__));
          ...
          #include    <stddef.h>  // offsetof()
          #define REG_OFFSET(reg)    offsetof(core::address_map, reg)
           
          bool chip::detect()
          {
              using namespace core;
              using namespace control;
              debug_header("Product ID read");
              uint8_t Product_id;
           
              if(!Transport.receive(Bus_address, REG_OFFSET(Product_ID), Product_id))
                  return disconnected();
           
              if(Product_id != core::PRODUCT_ID)
                  return failed();
              State = OK;
              return debug_ok();
          }

        Возможно, использование такого указателя поможет мне облагородить мой код.

        Цитата Qraizer @
        P.S. И да, они не указатели в том смысле, что не совместимы с простыми указателями на данные или функции. Даже с void*.
        Хм это уже вселяет пессимизм. С этими указателями вообще возможно сделать хоть что-то, кроме присваивания и разыменования?
          Цитата Dushevny @
          Возможно, использование такого указателя поможет мне облагородить мой код.
          Так а что из примера непонятно? Указатели хранят инфу об элементе класса, абстрагируясь от конкретного экземпляра. Сами по себе они никуда не указывают, и польза от них только при их применении к конкретному экземпляру. Даже разыменование такого указателя делается специальными операторами, содержащим конкретный this, а не обычной *, которая этого this предоставить не может. Разные экземпляры класса – разные результаты применения .* или ->* к указателю. Конечно, такие указатели обязаны ещё корректно учитывать наследование.
          Цитата Dushevny @
          Хм это уже вселяет пессимизм. С этими указателями вообще возможно сделать хоть что-то, кроме присваивания и разыменования?
          Ещё сравнения. А к чему там адресная арифметика? Что, хотя бы теоретически, могло бы быть результатом ++ к указателю? Обычно указатели на элементы классов используются тогда же, когда и обычные указатели: когда нет возможности или желания жёстко задавать имя подуказываемого объекта. Но обычные объекты могут быть объединены в массивы, а как быть с указателями на поля? К слову, над указателями на функции тоже нет адресной арифметики. Почему? За ненадобностью.
            Цитата Qraizer @
            Так а что из примера непонятно?
            Как именно заменить им offsetof(). Я привел пример своего кода, где offsetof() используется для получения адреса регистра в адресном пространстве микросхемы. Код работает, но автодополнение эклипсы при написании этого кода работать отказывается. Как там можно заменить offsetof() на такой указатель?
              Та как обычно, ставишь тип данных. Просто добавляешь к * область видимости.
              ExpandedWrap disabled
                uint8_t core::address_map::* ptr2ID = &core::address_map::Product_ID;
              Если у тебя где-то там есть экземпляр
              ExpandedWrap disabled
                core::address_map cpu;
              то доступ будет
              ExpandedWrap disabled
                cpu.*ptr2ID

              Но что-то мне подсказывает, что между экземплярами core и core::address_map не так всё просто.

              Добавлено
              И вообще, почему-то мне кажется, что cpu – это синглон, а в этом случае тебе не нужен ни указатель на поле структуры, ни offsetof(). Просто берёшь адрес поля экземпляра и получаешь обычный поинтер.

              Добавлено
              ExpandedWrap disabled
                Transport.receive(&cpu.Product_ID, Product_id);
              Понятно, что Transport.receive() требует определённых соглашений, которые мне неизвестны, но вопрос о синглоне, а значит и об отсутствии необходимости в параметризации имени поля структуры под указателем, это не отменяет, т.к. экземпляр класса сиречь this известен заранее.
              Сообщение отредактировано: Qraizer -
                Цитата Qraizer @
                Но что-то мне подсказывает, что между экземплярами core и core::address_map не так всё просто.
                core -это namespace. Экземпляра core::address_map тоже не существует, используется только смещение членов core::address_map от ее начала, это смещение и добывается при помощи offsetof().
                Прикреплённая картинка
                Прикреплённая картинка
                  Ну так если тебе нужно смещение, то offsetof() тебе и нужен. Указатели на элементы класса нужны как раз для того, чтобы не заморачиваться внутренней структурой класса и при этом чётко следить за типами.
                  Если так уж хочется притянуть сюда Плюсовые фичи, то нужно менять интерфейс с железом. К примеру:
                  ExpandedWrap disabled
                    /* linker script */
                    mcu_mbar : origin = 0x80000000, length = 0x00008000
                    MBAR = ADDR(mcu_mbar);
                  ExpandedWrap disabled
                    struct MemAddr
                    {
                      union
                      {
                        unsigned int CS0STR;
                        unsigned int CS0STP;
                        unsigned int CS1STR;
                        /* ... */
                        unsigned int CS7STP;
                      };
                      unsigned char dummy[0x100];
                    };
                    struct MemCntr
                    {
                      union
                      {
                        unsigned int SDRAMMode;
                        unsigned int SDRAMCtrl;
                        unsigned int Config1;
                        unsigned int Config2;
                      };
                      unsigned char dummy[0x100];
                    };
                    struct CDM
                    {
                      union
                      {
                        unsigned int CDM_JTAG_ID;
                        /* ... */
                        unsigned int CDM_PSC6CCR;
                      };
                      unsigned char dummy[0x100];
                    };
                    /* ... */
                    struct RegSpace
                    {
                      MemAddr systemSpace;
                      MemCntr SDRAM_control;
                      CDM     clockModule;
                      /* ... */
                    };
                     
                    extern unsigned char MBAR[];
                    volatile RegSpace &regMap = *reinterpret_cast<RegSpace*>(MBAR);


                  Добавлено
                  Ну и насобачить чё-нить:
                  ExpandedWrap disabled
                    template <typename CpuArea, typename RegType, typename T>
                    RegType out_reg(RegType CpuArea::* regPtr, T value, volatile CpuArea& cpu)
                    {
                      return cpu.*regPtr = value;
                    }
                     
                    template <typename CpuArea, typename RegType>
                    RegType in_reg(RegType CpuArea::* regPtr, volatile CpuArea& cpu)
                    {
                      return cpu.*regPtr;
                    }
                     
                    template <typename CpuArea, typename RegType>
                    RegType in_reg(RegType CpuArea::* regPtr, CpuArea RegSpace::* unit)
                    {
                      return regMap.*unit.*regPtr;
                    }

                  Юзать как так:
                  ExpandedWrap disabled
                    auto clck = &RegSpace::clockModule;
                     
                    out_reg(&CDM::CDM_PSC6CCR, 7, regMap.*clck);
                    std::cout << in_reg(&MemCntr::Config1, &RegSpace::SDRAM_control);
                  Как по мне, красиво, но непонятно.
                  Сообщение отредактировано: Qraizer -
                    вот хорошая статья на тему.
                    https://www.rsdn.org/article/cpp/fastdelegate.xml

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

                    надуманные примеры для демонстрации синтаксиса С++ новичкам;
                    реализация делегатов!
                      Статье 20 лет, она очень старая. И автор, похоже, просто не понимает толком, о чём пишет. Что вполне объяснимо, в то время язык большинством программистов ещё находился в стадии исследования.
                      • Автор зациклен на делегатах. Такое впечатление, что других предназначений для указателей на методы он просто не видит. Ну что сказать... в Плюсах нет интерфейсов, и поначалу это ставили ему в вину. Недолго, потом перестали, когда осознали, что с их ролью прекрасно справляются абстрактные классы, но абстрактные классы умеют и многое другое, что недоступно интерфейсам.
                      • Автора ставит в тупик необычные свойства указателей на методы, применяемые в пределах иерархий классов. Если б он капельку подумал, то легко бы понял, почему они такие. Почему разрешён неявный каст ссылок на производные классы к публичным базовым классам и почему для указателей на методы с точностью до наоборот, для меня, например, очевидно.
                      • Автор при кастах между классами иерархии обсуждает reinterpret_cast<>. ... ... ... Что?? По ходу он вообще не понимает о чём пишет. И дело тут вообще не в указателях на методы. Внутри полиморфной иерархии reinterpret_cast<> всегда (ну почти) неопределённое поведение! Только static_cast<> или dynamic_cast<>. (const_cast<> вне контекста обсуждения.) Для указателей на методы в том числе, они не исключение.
                      • Автор удивляется на касты по иерархиям с множественным наследованием. Тут надо признать, что проблема не так очевидна. Я просто оставлю тут вот это, где даже множественного наследования нет:
                        ExpandedWrap disabled
                          // нет метода
                          class A
                          {
                          public:
                            virtual ~A(){}                // просто чтоб был полиморфным
                          };
                           
                          // метод определён
                          class B: public A
                          {
                          public:
                            virtual void foo() {}
                          };
                           
                          // прямой вызов (попытка)
                          void f(A& a)
                          {
                          //  a.foo();            // ожидаемо не скомпилится
                          }
                           
                          // косвенный вызов (попытка)
                          void g(A& a, void (A::*ptr)())
                          {
                            (a.*ptr)();           // скомпилится
                          }
                           
                          int main()
                          {
                            B b;                  // метод есть!
                           
                          //  g(b, &B::foo);      // не скомпилится, и правильно сделает
                            g(b, static_cast<void (A::*)()>(&B::foo));    // скомпилится, но ожидаемо упадёт в run-time, потому как для A в VMT ничего нет
                          }
                        Ну а чего вы ожидали от того, что невозможно чекнуть в run-time (правильно, предупреждения), особенно если всё-таки вбить этот код в компилер кувалдой. А теперь добавьте туда множественные базы. Не виртуальные и без dynamic_cast<>. Надеюсь, сегодня автор лучше разбирается в предмете. Вообще, всё, что он написал там и далее касательно опасностей суть просто нарушение ODR, только очень замаскированное. Статика же чекается однозначно ещё при компиляции: error.
                      • На предмет рассмотрения хака из MFC могу сказать, что тогда их компилятор не умел то, что следовало бы уметь по Стандарту. Правда, использование MFC усложнилось бы, но без хака там всё реализуется. Я это делал в мультиметодах, прекрасно всё компилится и работает.
                      По теории это всё. За практику ничего не буду.

                      P.S. Большинство проблем с перекрёстным кастом указателей на методы снимается, если попросить компилятор всегда учитывать наихудшие случаи. Для MSVC это ключик /vmg. Тогда код в примере выше даже отработает правильно, ибо компилятор (наверное) нагенерит thunk к какому-нибудь аналогу "pure virtual call", и пусть они даже не вызываются, достаточно, чтобы в VMT что-то было и корректно позднесвязалось.

                      Добавлено
                      P.P.S. Статья реально очень старая. Уже 12 лет назад описанные в ней делегаты легко реализовывались биндами this в лямбды. В 2004-ом конечно всё было сложнее. И тем не менее даже тогда забиндить this в функциональный объект было несложно. Помню, как тут где-то в Холиварах писал подобное, только на предмет пропертей, а не делегатов.
                      Сообщение отредактировано: Qraizer -
                        Qraizer, тема понятная давно, но с практической точки зрения, остается какой-то мутной, лично для меня. У тебя есть примеры, когда использование указателей на методы (а тем более - указатели на поля) класса - решали бы какие-то задачи, которые иначе решить невозможно. Ну или решение было бы такое оптимизированное, что стоило бы этим заморачиваться в обязательном порядке?
                          Ну а часто ли тебе нужен offsetof(), Majestio? Необходимость в указателях на поля будет не намного чаще. Но когда она возникнет, не будет стирания типов и уменьшится человеческий фактор из-за ошибок в адресной арифметике.
                          Я использовал. Не то чтобы прям без них никак, но удобно (кусочек):
                          ExpandedWrap disabled
                              comPort[BitRate ]=uart_rate;
                              comPort[StopBits]=stop_bits;
                              comPort[fDTRCtrl]=DTR_CONTROL_ENABLE; // всегда готовы принимать
                              comPort[fXonXoff]=FALSE;              // управление передатчиком при приёме программных сигналов
                              comPort[fNullRcv]=
                              comPort[fErrRplc]=
                              comPort[fErrCtrl]=FALSE;
                              comPort[fBinary ]=                    // данные бинарные
                              comPort[fParity ]=TRUE;
                              comPort[readChar] =MAXDWORD;          // при чтении ждём...
                              comPort[readMult] =0;                 // ... с первого символа...
                              comPort[readAdd ] =0;                 // ... и до первой паузы
                              comPort[writeMult]=0;                 // записываем без пауз...
                              comPort[writeAdd] =1000;              // ... до секундого запрета передачи
                          В классе CComm:
                          ExpandedWrap disabled
                              TProp    operator[](IProp&)   const;          // Свойства
                              TTimeOut operator[](ITimeOut&)const;
                          Пропертя:
                          ExpandedWrap disabled
                            class TProp { /* ... */ };
                             
                            class IPropDWord: public IProp { /* ... */ };
                            class IPropWord: public IProp { /* ... */ };
                            class IPropByte: public IProp { /* ... */ };
                            class ITimeOut { /* ... */ };
                             
                            IPropDWord BitRate  (&DCB::BaudRate );
                            IPropByte  ByteSize (&DCB::ByteSize );
                            IPropByte  StopBits (&DCB::StopBits );
                            IPropByte  Parity   (&DCB::Parity   );
                            /* ... */
                            ITimeOut   readChar (&COMMTIMEOUTS::ReadIntervalTimeout);
                            ITimeOut   readMult (&COMMTIMEOUTS::ReadTotalTimeoutMultiplier);
                            ITimeOut   readAdd  (&COMMTIMEOUTS::ReadTotalTimeoutConstant);
                            ITimeOut   writeMult(&COMMTIMEOUTS::WriteTotalTimeoutMultiplier);
                            ITimeOut   writeAdd (&COMMTIMEOUTS::WriteTotalTimeoutConstant);
                          Конфигурирование через пропертя. 20 лет назад казалось прикольным.
                          Вот ещё пример из кода заказчика. Шелезяка. У него восемь ADC, разбитных по 8-и регионам в адресном пространстве, и каждый сколько-то там регистров. В заголовках процессора ADC представлен структурой, а все ADC 8-ю соответствующими указателями на абсолютные адреса этих регионов. Удобно? Вполне. Но вот ОСи нередко требуется с ними обращаться в цикле. А циклу имена не передашь, он хочет индексы. Что они сделали? Правильно догадался: создали массив из указа... в смысле offsetof()-ов на поля, на Cях писано.

                          Добавлено
                          С указателями на методы аналогично. Но и сложнее. Вообще, было бы просто странно, если б были указатели на поля, но не было бы на методы. С другой стороны... вот когда нам нужна параметризация поведения, что мы делаем в C? У нас там есть указатели на функции. В Плюсах они, вообще говоря, уже не так востребованы, потому что у нас есть полиморфизм. Те же указатели, но скрытые под капотом и управляемые компилятором. Поэтому указатели на методы всплывают там, где требуется ещё более глубокая параметризация. Мне она понадобилась в том же контексте, что у заказчика с его ADC. Мне нужно было собрать методы в массив и индексировать.
                          ExpandedWrap disabled
                            /* ... */
                                // внутренняя VMT - массив методов Accept();
                                // в отличие от RTTI-"матрицы" sheet, у каждого параметра мультиметода она своя и потому
                                // должна строиться в run-time, чем конструкторы LastAcceptorCaller и занимаются
                                ret_type (MD::*accepts[Length<typename CTL::Head::TypeList>::value])(param_type);
                             
                            /* ... */
                             
                              // это все апцепторы в иерархии, кроме самого базового
                              template <typename L, typename R, typename CTL, typename PTL, typename TPL, typename SRC,
                                        typename SHT, typename MD>
                              struct IterAcceptorCaller<ret_type, TList<L, R>, CTL, PTL, TPL, SRC, SHT, MD> :
                                                    public IterAcceptorCaller<ret_type, R, CTL, PTL, TPL, SRC, SHT, MD>
                              {
                            /*... */
                                /* восстановление типа очередного параметра, генерация следующего акцептора, передача ему
                                   следующего среза списка акцепторов, базовых типов параметров мультиметода, RTTI-матрицы итп
                                   и накопленной восстановленной информации о динамических типах и его вызов. */
                                typedef typename MostBase<typename CTL::Head::TypeList>::type   most_base;
                                typedef typename CTL::Head::template ParamType<most_base>::type param_type;
                                ret_type Accept(param_type arg)
                                {
                                  typedef typename SHT::base_type SheetType;
                                  typedef typename AcceptorMaker<ret_type, typename CTL::Tail, TList<arg_type, PTL>,
                                                                           typename TPL::base_type, SRC, SheetType>::type acceptor;
                                  // следующий акцептор
                                  acceptor a(base_type::m_Params, static_cast<typename TPL::base_type&>(base_type::m_Args),
                                             static_cast<const SheetType&>(base_type::m_Sht));
                                  // поиск в RTTI-массиве элемента, соответствующего динамическому типу пришедшего в диспетчер
                                  // аргумента, и получение его индекса в исходном списке типов, описывающем его иерархию
                                  auto idx = std::lower_bound(std::begin(base_type::m_Sht.get()), std::end(base_type::m_Sht.get()),
                                                              details::TypeInfo(CTL::Tail::Head::deref(GetField<0>(base_type::m_Args))));
                             
                                  // т.к. поиск не обязан давать точное совпадение и может только указать место в сортированном
                                  // контейнере, где ему было бы самое место, нужно самостоятельно убедиться в том, что элемент
                                  // успешно найден; в противном случае это означает ошибку в описании списка типов в иерархии
                                  if ( idx == std::end(base_type::m_Sht.get()) ||
                                      !CTL::Tail::Head::check(*idx, CTL::Tail::Head::deref(GetField<0>(base_type::m_Args))))
                                    throw std::invalid_argument("IterAcceptorCaller<> error: unlisted parameter");
                                  // индексируем внутреннюю VMT, вызывая Accept() того акцептора, чей индекс вернул поиск
                                  // в RTTI-массиве, и передавая аргумент мультиметода, т.с. восстанавливая его тип;
                                  // в результате итерируемся к обработке следующего параметра
                                  return (a.self ->* a.accepts[idx->index()])(GetField<0>(base_type::m_Args));
                                }
                              };
                            /* .. */
                              // это базовый в иерархии акцептор; весь список типов иерархии параметра уже обработан производными
                              // классами, так что этот с ними уже не работает, он только обслуживает внутреннюю VMT
                              template <typename CTL, typename PTL, typename TPL, typename SRC, typename SHT, typename MD>
                              struct LastAcceptorCaller<ret_type, NullType, CTL, PTL, TPL, SRC, SHT, MD>
                            /* ... */
                          Весь код можно увидеть на GitHab-е или у нас в темах по мультиметодам. Для восстановления динамического типа используется RTTI, методика основана на предварительном заполнении сортированного массива проксями к std::type_info на основе std::type_info::before() с последующим поиском в нём восстанавливаемого параметра. В итоге имеем индекс. Преобразование индекса в тип осуществляется созданием иерархии акцепторов, шаблонных классов, конкретизируемых нужным типом каждый. Чей XXXXAcceptorCaller::Accept() вызвался, тот аргумент шаблона и восстановлен. Как-то так...

                          Добавлено
                          Вообще, наличие инструмента подразумевает, что где-то он полезен. Тот факт, что он маловостребован, не означает, что он не нужен. Если указатели на поля при их отсутствии можно моделировать offsetof(), то вот для указателей на методы альтернативы нет. К тому же, тут спорить не буду, легко можно не понимая инструмента, не заметить, что вот конкретно вот тут вот ему самое место и, даже если знаешь о его наличии, в итоге накодить костыль.
                          Сообщение отредактировано: Qraizer -
                            Цитата Qraizer @
                            Ну а часто ли тебе нужен offsetof(), Majestio? Необходимость в указателях на поля будет не намного чаще. Но когда она возникнет, не будет стирания типов и уменьшится человеческий фактор из-за ошибок в адресной арифметике.
                            Я использовал. Не то чтобы прям без них никак, но удобно (кусочек):

                            Хе-хе ;) Вставлю свои пять копеек. Ты же знаешь, ну или может быть помнишь - моей "нормальной" стартовой базой входа в программинг был Пасквиль, сперва Turbo, потом Virtual, и потом очень немножечко Дэлфи. Все эти "рéкорды" я полюбил сразу, как родных... Но потом я повстречал Perl :lol: Там только скаляры, вектора и хэши (на слэнге С++ "упорядоченные карты", ну или просто "карты")

                            И сразу всё смотрится как-то иначе, а зачем нам куча предопределенных полей какой-то железяки, если в перспективе их будут тыщчы или даже стопицот, возможно тыщ???

                            Простой "Перловский" подход - "не знаешь что будет - загоняй всё в хэши" :rolleyes: А-б-и-с-ь-н-я-ю свою точку зрения ... Линейка продуктов имеет в "прапертях" всё неугомонно расширяющуюся "палитру" прапертей, ну не угнацца щит (Q)! Но и мы сами с усами ...

                            1) Если не парить быстродействие, помним - загоняем всё в хэши
                            2) А если быстродействие парит - загоняем в вектора и именуем индексы enum'ами, при необходимости используем страшную клизму

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

                            Цитата Qraizer @
                            но удобно (кусочек)

                            Если надо - код запилю. Но не мне тебе код писать, ты и сам уже всё прекрасно понимаешь и визуализируешь ;)
                            Сообщение отредактировано: Qraizer -
                              Цитата Majestio @
                              Простой "Перловский" подход - "не знаешь что будет - загоняй всё в хэши"
                              У "нас" загоняют в вектора. Ну, у меня был известен размер, так что массив. O(1) рулит. За наносекунды если... RTTI не рассматриваю, а вот вариант реализации на Visitor спорит с "нативной" реализацией, описанной у отца-основателя, но так и не реализованной в Стандарте. И это притом, что у него там двупараметрические, а у меня произвольные, причём ещё и с определяемой связностью параметров: где надо, позднее, где не надо, раннее. Как скажешь, так и будет. Ваши не конкуренты, в общем.

                              P.S. Интересно ещё было бы сравнить с языками с искаробочной поддержкой множественной динамической диспетчеризации. Насколько я понял, самая прозрачная поддержка у Common Lisp-а, но что-то я там не увидел декларативности в сопоставлении, только тупое полное перечисление всех вариантов комбинаций. Ну т.е. если у меня, скажем, три иерархии по десятку классов в каждой, то будь добр накидать 103 переопределений. Хотя могу ошибаться, не спец в нём.
                                Скрытый текст
                                Цитата Qraizer @
                                С пятницей, Majestio!

                                Ну тя и чуйка! :blink: С 9 мая а ограничивал свою диету в плане алкоголя, и только сёння решился отведать студеной в морозильнике воткэ ... С разными очень вкусными яствами! :blink:

                                Про отца-основателя не нужно - не асилим, давай на пальцах, ога? Я тебя спрашиваю про "практическое применение" а ты сорян "съезжаешь" в мульти-методы. Нет, мульти-методы "в вакууме" не нужны - нужен практический пример. Но и даже не тут !!! Мы же пока обсуждаем просто поля классов и ссылки на них. Про методы и мульти-методы поговорим потом.

                                Итак, повтор вопроса, чем ценны ссылки на поля и пример их использования для достижения высшего качества?

                                есть что сказать и показать на примерах?
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0958 ]   [ 18 queries used ]   [ Generated: 19.04.24, 01:24 GMT ]