Nano Hash - криптовалюты, майнинг, программирование

Контейнер производных объектов/умных указателей

Допустим, у меня есть:

class Base {...};
class Derived1 : public Base {...};
class Derived2 : public Base {...};
class Derived3 : public Base {...};

class Store {
public:
    void Add(const Base&);    //Adds mix of Derived1/2/3
private:
    vector<const Base*> vec;    
    vector<shared_ptr<const Base> > vec_smart;
};

//------------------------------------------------------

void Store::Add(const Base& b){
    vec.push_back(&b);    //got sliced
}

При использовании вектора указателей на Base он нарезался. Я полагаю, мне нужно использовать умные указатели, но я не могу заставить его работать.

Я пробовал что-то вроде:

auto tmp = make_shared<const Base> (b);
vec_smart.push_back(shared_ptr<const Base>(b));

Но все равно порезался. Что я делаю неправильно?

РЕДАКТИРОВАТЬ: у меня есть оператор ‹‹ в базовом классе, который вызывает виртуальную печать в производных классах.

ostream & operator <<(ostream & os, const Base & x) {
    x.print(os);
    return os;
}

void Base::print(ostream& os) const {
   os << "Base";
}

void Derived1::print(ostream& os) const {
   os << "Derived1";
}

когда я звоню

cout << b;

В Store::Add он выводится нормально, но когда я перебираю вектор после его сохранения, все, что я получаю, это «База»

ostream & operator <<(ostream & os, const Store & x) {
    for (auto it = x.vec.begin(); it != x.vec.end(); ++it) {
        os << *(*it) << endl;
    }
    return os;
}

Это плохой дизайн?


  • Как вы определили, что он порезан? Он не может быть нарезан, если это указатель. 20.04.2014
  • make_shared<const Base>(b) выполняет срез. vec.push_back(&b) ничего не нарезает. shared_ptr<const Base>(b) возможно даже не компилируется. 20.04.2014

Ответы:


1

Я предполагаю, что вы не объявили соответствующие методы в Base как virtual. Попробуй это:

struct Base
{
  virtual void print(std::ostream& os) const { os << "Base"; }
  virtual ~Base() {}
};

struct Derived1 : Base
{
  void print(std::ostream& os) const { os << "Derived1"; }
};

и так далее. Примечание. Я использовал здесь только struct, чтобы не набирать public несколько раз.

Вот рабочий пример:

#include <vector>
int main()
{
  Base b;
  Derived1 d;
  std::vector<const Base*> v{&b, &d};

  for (auto it = v.cbegin(); it != v.cend(); ++it)
  {
    std::cout << *(*it) << std::endl;
  }

}

Выход:

Base
Derived1

Вы можете увидеть это в действии здесь.

Изменить Ваш код имеет неопределенное поведение, потому что вы храните указатели на временные объекты:

Store a("aaaaaaa");
a.Add(Derived("abc", 5));
a.Add(Derived("def", 6));

Эта версия работает так, как ожидалось:

Store a("aaaaaaa");
Derived d0("abc", 5);
Derived d1("def", 6);
a.Add(d0);
a.Add(d1);

Редактировать 2: из ваших комментариев:

Допустим, я вынужден использовать a.Add(Derived("abc", 5)); Что я могу сделать с этим в моей реализации?

Вы можете сделать Add шаблоном:

template <typename T>
void Add(const T& elem)
{
  vec.push_back(new T(elem));
}

or

template <typename T>
void Add(const T& elem)
{
  vec_smart.push_back(std::make_shared(elem));
}
20.04.2014
  • Отредактировал мой вопрос. Я должен ошибаться в своем дизайне. 20.04.2014
  • @Bilcus Вы не показали ключевую часть. Ваша проблема согласуется с моим предположением, что ваш участник не virtual. Я отредактировал свой пост, чтобы использовать методы, аналогичные вашим. 20.04.2014
  • Это в основном мой код и проблема с ним. Перед сохранением в векторе он выводится нормально, но после этого нет. @juanchopanza 20.04.2014
  • Код @Bilcus Yuor имеет неопределенное поведение. Вы храните указатели на временные объекты. 20.04.2014
  • О, спасибо теперь вижу. Могу ли я получить подсказку о том, как реализовать это правильно? Это где умные указатели вступают в игру? 20.04.2014
  • Последняя вещь. Допустим, я вынужден использовать a.Add(Derived("abc", 5)); Что я могу сделать с этим в своей реализации? 20.04.2014
  • Могу ли я получить подсказку, пожалуйста, на мой предыдущий вопрос? 20.04.2014
  • @Bilcus Я кое-что добавил. 20.04.2014
  • Вау, идеально. Большое спасибо. В итоге я получил несколько операторов if, которые работали, но были уродливыми. Это просто идеально. 20.04.2014
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

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

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..