Хранение унаследованного класса в векторе [дубликат]

Использование GNU Parallel выглядит так:

#!/bin/bash
echo_var(){
    echo $1
    return 0
}
export -f echo_var
seq -f "n%04g" 1 100 | parallel -P 10 echo_var {} 
exit 0

Если вы используете версию 20170822, вам даже не нужно export -f, пока вы это запустили:

. `which env_parallel.bash`
seq -f "n%04g" 1 100 | env_parallel -P 10 echo_var {} 
4
задан WhozCraig 21 April 2013 в 01:18
поделиться

4 ответа

Нет, это не будет.

vector<Instruction> ins;

хранит значения, а не ссылки. Это означает, что независимо от того, как вы, но этот объект Instruction там, он будет скопирован в какой-то момент в будущем.

Кроме того, поскольку вы выделяете new, приведенный выше код течет, что объект. Если вы хотите сделать это правильно, вам нужно будет

vector<Instruction*> ins

Или еще лучше:

vector< std::reference_wrapper<Instruction> > ins

Мне нравится в этом блоге для объяснения reference_wrapper

Это поведение называется срезом объектов .

8
ответ дан jozefg 26 August 2018 в 06:56
поделиться

Итак, вам понадобится какой-то указатель. A std::shared_ptr работает хорошо:

typedef shared_ptr<Instruction> PInstruction;

vector<PInstruction> v;
v.emplace_back(make_shared<Add>());

PInstruction i = v[0];

Имейте в виду, что PInstruction подсчитывается по ссылке, поэтому конструктор копирования PInstruction создаст новую «ссылку» на тот же объект.

Если вы хотите сделать копию ссылочного объекта, вам придется реализовать метод clone: ​​

struct Instruction
{

   virtual PInstruction clone() = 0;
   ...
}

struct Add
{
    PInstruction clone() { return make_shared<Add>(*this); }
    ...
}

PInstruction x = ...;
PInstruction y = x->clone();

Если производительность является проблемой, чем вы можете посмотреть на std::unique_ptr, это немного сложнее управлять, поскольку семантика перемещения всегда требуется, но она позволяет избежать затрат на некоторые атомные операции.

Вы также можете использовать необработанные указатели и управлять памятью вручную с помощью какой-либо архитектуры пула памяти.

Основная проблема заключается в том, что для получения полиморфного типа компилятор не знает, насколько велики будут подклассы, поэтому вы не можете просто иметь вектор базового типа, так как он не будет иметь дополнительное пространство, необходимое для подклассов. По этой причине вам нужно будет использовать семантику pass-by-reference, как описано выше. Это сохраняет указатель на объект в векторе, а затем сохраняет объект в куче в блоках разных размеров в зависимости от того, что требуется подклассу.

4
ответ дан Andrew Tomazos 26 August 2018 в 06:56
поделиться

Нет, это не сработает; вы «нарезаете» объект Add и вставляете только его Instruction часть в массив. Я бы рекомендовал вам абстрагировать базовый класс (например, сделав execute чисто виртуальным), так что нарезка дает ошибку компиляции, а не неожиданное поведение.

Чтобы получить полиморфное поведение, вектор должен содержать указатели на базовый класс.

Затем вам нужно быть осторожным, как вы управляете самими объектами, поскольку они больше не содержатся в векторе. Разумные указатели могут быть полезны для этого; и поскольку вы, вероятно, будете динамически распределять эти объекты, вы также должны дать базовому классу виртуальный деструктор, чтобы убедиться, что вы можете их правильно удалить.

1
ответ дан Mike Seymour 26 August 2018 в 06:56
поделиться

Возможно, вы захотите сделать пару вещей: A: изменить тип «v» на «вектор», B: управлять вашей памятью с помощью оператора «delete». Чтобы ответить на ваш вопрос, при таком подходе, да, но вы сможете получить доступ к интерфейсу только из «Инструкции», если вы ЗНАЕТ тип чего-то, на который указывает указатель «Инструкция», я бы предложил использовать dynamic_cast, если вам нужно доступ к интерфейсу, скажем, «Добавить».

0
ответ дан The Floating Brain 26 August 2018 в 06:56
поделиться
Другие вопросы по тегам:

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