Полиморфизм типа возврата для передачи значением

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

Первоначально, у меня было что-то как:

class Operand;

Operand genOperandA() { ...; return Operand(); }
Operand genOperandB() { ...; return Operand(); }
... // more operand-generation functions

typedef Operand (*OpGen)();

// Table of function pointers
static const OpGen generators[] =
{
    genOperandA,
    genOperandB,
    ...
};

// Function to do some operation on the operand
void operate(Operand& op);

...

// Example call
operate(generators[1]());

Пока неплохо (я думаю). Однако существует теперь несколько полученных типов операнда, например. class RegisterOperand : public Operand. Я имею новый, выделенный genOperand функции, которые идеально возвратили бы экземпляры производных типов. Но я не могу сделать этого:

Operand genOperandC() { ...; return RegisterOperand(); }

и я не могу сделать этого:

RegisterOperand genOperandC() { ...; return RegisterOperand(); }

static const OpGen generators[] = 
{
    ...
    genOperandC,
};

Однако я знаю, что это работало бы, если бы я должен был возвратить ссылочные типы или типы указателей, таким образом, единственная опция, которую я в настоящее время имею, является чем-то как:

Operand *genOperandC() { ...; return new RegisterOperand(); }

который теперь требует явной очистки, которая не была необходима первоначально.

Какие-либо альтернативы я не рассмотрел?

11
задан Oliver Charlesworth 21 June 2010 в 08:12
поделиться

2 ответа

Могут быть и другие конструкции, которые не требуют использования указателей, но если вам нужно или вы хотите пойти по этому пути, это может вас заинтересовать.


Если возврат указателя является проблемой (из-за необходимости «навести порядок»), вам определенно следует рассмотреть возможность использования интеллектуальных указателей в качестве возвращаемого типа.

Вот пример вашего фабричного метода с интеллектуальными указателями:

boost::shared_ptr<Operand> genOperandC()
{
  return boost::shared_ptr<Operand>(new RegisterOperand());
}

Таким образом, вам не придется вручную вызывать delete : это будет делать деструктор boost: : shared_ptr для вас, когда потребуется.

Если впоследствии вам нужно преобразовать результирующий указатель, boost также предоставляет функции преобразования:

boost::shared_ptr<Operand> op = genOperandC();

boost::shared_ptr<RegisterOperand> rop =
  boost::dynamic_pointer_cast<RegisterOperand>(op);
4
ответ дан 3 December 2019 в 09:40
поделиться

Вы можете обернуть:

class Operand
{
public:

private:
  std::unique_ptr<OperandImpl> mImpl;
};

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

7
ответ дан 3 December 2019 в 09:40
поделиться
Другие вопросы по тегам:

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