问题
I'm not sure if the question title is accurate... Let me start by explaining my original simple scenario, and then move on to explain what would I like to do, but can't.
Originally, I had something like:
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]());
So far so good (I think). However, there are now several derived operand types, e.g. class RegisterOperand : public Operand
. I have new, dedicated genOperand
functions that ideally would return instances of the derived types. But I can't do this:
Operand genOperandC() { ...; return RegisterOperand(); }
and I can't do this:
RegisterOperand genOperandC() { ...; return RegisterOperand(); }
static const OpGen generators[] =
{
...
genOperandC,
};
However, I know this would work if I were to return reference or pointer types, so the only option I currently have is something like:
Operand *genOperandC() { ...; return new RegisterOperand(); }
which now requires explicit cleanup which wasn't necessary originally.
Any alternatives I haven't considered?
回答1:
There might be other designs that doesn't require you to use pointers, but if you need or want to go this way, this might interest you.
If returning a pointer is a problem (because of the need to "clean-up" things), you definitely should consider using smart pointers as return type.
Here is an example of your factory method with smart pointers:
boost::shared_ptr<Operand> genOperandC()
{
return boost::shared_ptr<Operand>(new RegisterOperand());
}
This way, you won't have to call delete
manually: it will be done by the destructor of boost::shared_ptr<Operand>
for you when required.
If afterwards you need to cast the resulting pointer, boost
provides casting functions as well:
boost::shared_ptr<Operand> op = genOperandC();
boost::shared_ptr<RegisterOperand> rop =
boost::dynamic_pointer_cast<RegisterOperand>(op);
回答2:
You can wrap:
class Operand
{
public:
private:
std::unique_ptr<OperandImpl> mImpl;
};
This is similar to a Strategy Pattern: the actual operand behavior is hidden, and accessible through a Non-Virtual Interface. The user get a copy of Operand
, she does not need to know anything about its internal and can use it, and you are free to implement various derived behaviors.
回答3:
I know this question was asked some time ago but I recently bumped into this problem myself and I came up with a different solution that I though could be helpful here.
So the idea is to make a wrapper to manage the pointer but to also support copying the wrapper unlike the unique pointer which can only be moved.
class PolymorphicType {
public:
/*
Class interface ...
*/
PolymorphicType() { it = nullptr; }
virtual ~PolymorphicType() { if(it != nullptr) delete it; }
PolymorphicType& operator=(const PolymorphicType& org) {
//Clone the derived type and store it
if(org.it != nullptr)
it = org.it->clone();
}
private:
Base* it;
};
Each derived class must now implement it's own clone method and you are good to go! And just in case here is a nice post explaining how cloning of derived types works: Copying derived entities using only base class pointers, (without exhaustive testing!) - C++
Hope this helps someone out!
来源:https://stackoverflow.com/questions/3082995/return-type-polymorphism-for-pass-by-value