传递值的返回类型多态性

时间:2010-06-21 08:12:02

标签: c++ polymorphism

我不确定问题标题是否准确......让我先解释一下我原来的简单场景,然后继续解释我想做什么,但不能。

最初,我有类似的东西:

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(); }

现在需要明确的清理,这是原来不必要的。

我还没有考虑过任何替代方案?

4 个答案:

答案 0 :(得分:7)

你可以包装:

class Operand
{
public:

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

这与策略模式类似:实际的操作数行为是隐藏的,可通过非虚拟接口访问。用户获得Operand的副本,她不需要知道任何有关其内部的内容并且可以使用它,并且您可以自由地实现各种派生行为。

答案 1 :(得分:4)

可能有其他设计不要求您使用指针,但如果您需要或想要这样做,这可能会让您感兴趣。


如果返回一个指针是一个问题(因为需要“清理”东西),你绝对应该考虑使用智能指针作为返回类型。

以下是使用智能指针的工厂方法示例:

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

这样,您就不必手动调用delete:在需要时,它将由boost::shared_ptr<Operand>的析构函数完成。

如果之后您需要投射结果指针,boost也提供了投射功能:

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

boost::shared_ptr<RegisterOperand> rop =
  boost::dynamic_pointer_cast<RegisterOperand>(op);

答案 2 :(得分:0)

这样的事情怎么样?

请注意,您不能简单地操作(generators [i]()),因为原始的operation()采用非const引用。

#include <iostream>
#include <string>
#include <memory>

class Operand {
public:
        Operand(std::string x = "Operand"): x(x) {}
        const std::string x;
};

class RegisterOperand: public Operand {
public:
        RegisterOperand(std::string x = "RegisterOperand")
                : Operand(x) {}
};

typedef std::auto_ptr<Operand> POperand;

POperand genOperandA() { return POperand(new Operand("genOperandA")); }
POperand genOperandB() { return POperand(new Operand("genOperandB")); }
POperand genOperandC() { return POperand(new RegisterOperand()); }
// more operand-generation functions

typedef POperand (*OpGen)();

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

void operate(const POperand& op)
{
        std::cout << op->x << std::endl;
}

int main()
{
        operate(generators[0]());
        operate(generators[1]());
        operate(generators[2]());
        return 0;
}

答案 3 :(得分:0)

我知道这个问题是前一段时间被问过的,但我最近自己遇到了这个问题,我想出了一个不同的解决方案,我在这里可能会有所帮助。

所以我的想法是创建一个包装器来管理指针,但也支持复制包装器,而不像只能移动的唯一指针。

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;
};

每个派生类现在必须实现它自己的克隆方法,你很高兴! 以防这里有一篇很好的文章解释了派生类型的克隆是如何工作的:Copying derived entities using only base class pointers, (without exhaustive testing!) - C++

希望这可以帮助别人!