设计建议 - 避免"无效的协变返回类型"返回子类时

时间:2015-07-14 11:52:53

标签: c++ c++11

我有以下情况:

我指定一个纯虚函数:

virtual PredictedMatch PredictMatch(const Match &match) const = 0;

我也有:

class ImpactPredictedMatch : public PredictedMatch

现在,我想做:

ImpactPredictedMatch PredictMatch(const Match &match) const;

在一个实现前面的纯虚函数的类中。我假设编译器会根据需要简单地转换返回的类型,但我得到:

impact_predictor.h:18:24: error: invalid covariant return type for ‘virtual ImpactPredictedMatch ImpactPredictor::PredictMatch(const Match&) const’ ImpactPredictedMatch PredictMatch(const Match &match) const;

我接受这只是在C ++中不起作用,但我真的希望你建议最好做什么。我必须返回指针吗?我真的不愿意,因为我喜欢自动内存管理,但这是唯一的方法吗?

感谢您的帮助!

2 个答案:

答案 0 :(得分:4)

当您返回更多派生类的实例时,调用代码可以期望存储在基类型的变量中。这样做的结果可能是切片,丢失数据并可能泄漏内存(最多)。如果需要协变返回类型,则唯一的选择是指针或引用类型。在这两种情况下,您都需要确保对象至少与指针/引用一样长。

答案 1 :(得分:1)

正如previous answer中所述,返回类型的协方差仅适用于指针或引用。

但是,您可以尝试使用name hidding模拟返回类型与值类型的协方差:

class Base {
public:
    // Non-virtual, simply delegates to the protected virtual method.
    // May be hidden in derived class in order to covariate the return type.
    PredictedMatch predictMatch(const Match &match) const {
        return this->doPredictMatch(match);
    }

protected:
    virtual PredictedMatch doPredictMatch(const Match &match) const = 0;
};

class Derived : public Base {
public:
    // Hides Base::predictMatch()
    ImpactPredictedMatch predictMatch(const Match &match) const;

private:
    // Delegates to the specialized non-virtual member above
    PredictedMatch doPredictMatch(const Match &match) const {
        return this->predictMatch(match);  // Slices the object
    }
};

隐藏会员通常不被视为良好做法或推荐的设计工具。根据您想要实现的特定类设计,它可能会或可能不会更好地通过指针或引用返回。

我使用名称隐藏的一种情况就像上面的例子一样,实现了一个多态的clone()方法,返回一个std::unique_ptr(而不是返回一个原始指针,并希望用户记得读取方法的文档和正确管理对象的生命周期)。

另请注意,此设计使用"值协方差"假定您可以安全地转换或切片返回的对象而不改变含义。如果情况并非如此,那么我相信按价值或参考价格返回是您唯一的选择。