Совет относительно лучшего способа расширить контейнер STL C++ с помощью пользовательских методов

Вам необходимо использовать render() в вашем Formik компоненте.

Что-то вроде:

<Formik render={({ values }) => {
  <Form>
    <FieldArray>
      ... use values
    </FieldArray>
  </Form>
}} />
12
задан sivabudh 25 March 2009 в 20:53
поделиться

8 ответов

почему Вы должны расширить вектор таким образом?

используйте стандарт <algorithm> с Вашими функторами.
например.

std::min_element, std::max_element

int max_a = std::max_element
        ( 
            v.begin(), 
            v.end(), 
            boost::bind( 
                std::less< int >(),
                bind( &Item::a, _1 ), 
                bind( &Item::a, _2 ) 
            )
        )->a;

std::accumulate - для вычисляют среднее число

const double avg_c = std::accumulate( v.begin(), v.end(), double( 0 ), boost::bind( Item::c, _1 ) ) / v.size(); // ofcourse check size before divide  

Ваш ItemList:: SpecialB () мог быть rewrited как:

int accumulate_func( int start_from, int result, const Item& item )
{
   if ( item.SpecialB() < start_from )
   {
       result -= item.SpecialB();
   }
   return result;
}

if ( v.empty() )
{
    throw sometghing( "empty vector" );
}
const int result = std::accumulate( v.begin(), v.end(), v.front(), boost::bind( &accumulate_func, v.front(), _1, _2 ) );

BTW: если Вам не нужен доступ к участникам, Вам не нужно наследование.

12
ответ дан 2 December 2019 в 03:04
поделиться

Это - плохая идея.

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

Для больше на этом, см. этот ответ на том, почему не произойти из std::string. Многие из тех же точек применяются:

Конструктор не работает на класс, наследованный от станд.:: строка

  • Никакой виртуальный деструктор
  • Никакие защищенные функции (таким образом, Вы ничего не получаете путем наследования),
  • Полиморфизм не будет работать, и Вы получите объектное разрезание. std::vector является присваиваемым, но если Вы добавите свои собственные поля, то они не будут скопированы на присвоении, если Вы присвоитесь от векторного указателя или векторной ссылки. Это вызвано тем, что vector operator= не знает о Ваших полях.

По всем этим причинам Вы - более обеспеченные служебные функции создания, чем расширение когда дело доходит до STL.

20
ответ дан 2 December 2019 в 03:04
поделиться

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

Heck при планировании его хорошо заставляют его работать с итераторами вместо индексов, и это будет работать с больше, чем просто std::vector (см. <algorithm> для некоторых очень хороших примеров).

Например, Вы могли использовать функтор для MaxA как это:

struct CmpA {
    bool operator()(const Item &item1, const Item &item2) { return item1.a < item2.a; }
}

const int result = std::max_element(v.begin(), v.end(), CmpA()).a;

Ваш specialB мог быть столь же простым с функтором и std::accumulate

Править: или для C++ 11 и позже, это может быть столь же просто как:

const int result = std::max_element(v.begin(), v.end(), [](const Item &item1, const Item &item2) {
    return item1.a < item2.a;
}).a;

Править: Вы спросили, почему лучше сделать это этот путь:

при использовании алгоритмов, шаблонов и итераторов, это будет работать, даже если Вы решите поместить объекты в a std::list<Item> или что бы то ни было. Это - просто больше versitile и помогает кодировать reuseablity.

Плюс функции в <algorithm> сделайте большую часть этого для Вас так, можно просто использовать мало 3 функтора линейного адаптера.

Править: В дополнение к этому tgamblin перечислил некоторые очень неопровержимые доводы для не наследования std::vector (и большинство других контейнеров станд., включая std::string).

11
ответ дан 2 December 2019 в 03:04
поделиться

Я предпочитаю использовать stl контейнеры в качестве детали реализации, а не в качестве части интерфейса моего решения. Таким образом, я могу изменить контейнеры (вектор для двухсторонней очереди или списка), если потребность возникает без какого-либо затрагиваемого кода вызова. Вам, вероятно, придется записать, что некоторые звонят через функции, но инкапсуляция стоит дополнительного ввода.

5
ответ дан 2 December 2019 в 03:04
поделиться

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

2
ответ дан 2 December 2019 в 03:04
поделиться

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

int MaxA(const std::vector<Item>& vec) {
    if(vec.empty()) {
        throw;
    }

    int maxA = vec[0].a;
    for(std::vector<Item>::const_iterator i = vec.begin(); i != vec.end(); ++i) {
        if(i->a > maxA) {
            maxA = i->a;
        }
    }
    return maxA;
}

Или существует станд.:: max_element, который сделал бы почти такой же... минус бросок, конечно.

1
ответ дан 2 December 2019 в 03:04
поделиться

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

1
ответ дан 2 December 2019 в 03:04
поделиться

Вы корректны, который Вы не должны наследовать от контейнеров STL. Виртуальные функции сделали бы их значительно больше - основной размер векторов спрыгнет с 12 - 16 байтов (в реализации, которую я использую). Помимо этого, виртуальные функции трудно встроить, который может замедлить код. Если Вы делаете массив миллиона главным-образом-пустых-векторов, различие складывает довольно быстро.

Можно все еще получить эффект, который Вы хотите путем объявления вектора как членской переменной в ItemList и затем преобразования через любые методы, которые Вы хотите выставить.

class ItemList {
private:
  std::vector< Item > mItems;
public:
  typedef std::vector< Item >::size_type size_type;
  int MaxA();
  int SpecialB();
  Item &operator[]( size_type offset ) { return mItems[offset]; }
  size_type size() const { return mItems.size(); }
};

... и т.д. Это - изрядное количество трудной работы, но она даст Вам эффект, который Вы попросили.

1
ответ дан 2 December 2019 в 03:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: