重写子类中的返回类型

Overriding return type in child class

本文关键字:返回类型 子类 重写      更新时间:2023-10-16

已知类IPrinterManager及其子类ColorPrinterManagerColorPrinterAbstractPrinter的子类。编译终止时显示消息ColorPrinterManager::print is not a covariant of IPrinterManager::print。我如何解决这个问题?

class IPrinterManager
{
public:
   virtual std::vector<std::shared_ptr<AbstractPrinter>>* print(std::string text) = 0;
};
class ColorPrinterManager : public IPrinterManager
{
public:
   std::vector<std::shared_ptr<ColorPrinter>>* print(std::string text);
};

您需要返回std::vector<std::shared_ptr<AbstractPrinter>>*。这是无可回避的。你仍然可以用ColorPrinter指针填充它。

协变返回类型允许指定更派生的类型,作为虚函数的返回类型。但是指针的 vectors没有这样的关系。


同样,考虑按值返回。有了NRVO和move语义,向量真的很擅长有效地管理它们的资源。

ColorPrinter可能来源于AbstractPrinter,但shared_ptr<ColorPrinter>不是来源于shared_ptr<AbstractPrinter>, vector<shared_ptr<ColorPrinter>>也不是来源于vector<shared_ptr<AbstractPrinter>>。所以你的print函数不是协变。

你需要坚持使用vector<shared_ptr<AbstractPrinter>>。当然,如果你有像

这样的代码
ColorPrinterManager pm;
auto v = pm.print(string("bla"));
for(auto &s : v) {
    // This gives you the AbstractPrinter
    auto p = s.get();
    // If you called ColorPrinterManager you know that all printers are ColorPrinter
    auto p2 = dynamic_cast<ColorPrinter*>(p);
}

如果您在这里确实需要协变返回类型,一种方法是在打印机容器的旁边定义一个并行的层次结构,并使用它来代替std::vector

// printers
class AbstractPrinter { ...
class ColourPrinter : public AbstractPrinter { ...
// printer collections
class AbstractPrinterCollection {
      public: virtual AbstractPrinter* get(int i) = 0; ...
class ColourPrinterCollection : public AbstractPrinterCollection {
      public: ColourPrinter* get(int i) override { ... }
      private: std::vector<std::shared_ptr<ColourPrinter>> vec; ...

注1:get返回的是普通指针,不是共享指针。这是因为我们需要它具有协变返回类型,而它不适用于智能指针。(有办法绕过它)。

注释2:在整个层次结构中只有叶子类有数据成员(就像一个实际的容器和实际的打印机),基类和中间类将数据委托给叶子,并且可以是完全抽象的。

注释3:在AbstractPrinterCollection中没有put(在叶子类中可能有put)。

注4:这是相当麻烦的。考虑使print 非虚拟(并按值返回)。