如何使用带有智能指针的协变返回类型?

ami*_*mit 63 c++ smart-pointers covariance

我有这样的代码:

class RetInterface {...}

class Ret1: public RetInterface {...}

class AInterface
{
  public:
     virtual boost::shared_ptr<RetInterface> get_r() const = 0;
     ...
};

class A1: public AInterface
{
  public:
     boost::shared_ptr<Ret1> get_r() const {...}
     ...
};
Run Code Online (Sandbox Code Playgroud)

此代码无法编译.

在视觉工作室,它提出

C2555:覆盖虚函数返回类型不同且不协变

如果我不使用boost::shared_ptr但返回原始指针,代码编译(我理解这是由于C++中的协变返回类型).我可以看到这个问题是因为boost::shared_ptrRet1不是源自boost::shared_ptrRetInterface.但我想返回boost::shared_ptrRet1在其他类使用,否则我必须在返回后投返回值.

  1. 难道我做错了什么?
  2. 如果没有,为什么这样的语言 - 它应该是可扩展的,以处理这种情况下智能指针之间的转换?有一个理想的解决方法吗?

Ant*_*ams 24

首先,这确实是它在C++中的工作原理:派生类中虚函数的返回类型必须与基类中的相同.有一个特殊的例外,一个返回一个类X的引用/指针的函数可以被一个函数覆盖,该函数返回一个从X派生的类的引用/指针,但是你注意到它不允许智能指针(例如shared_ptr),仅用于普通指针.

如果您的界面RetInterface足够全面,那么您将不需要知道调用代码中的实际返回类型.一般来说它无论如何都没有意义:原因get_rvirtual函数首先是因为你将通过指针或对基类的引用来调用它AInterface,在这种情况下你不知道派生类会是什么类型返回.如果您使用实际A1引用来调用它,您可以创建一个单独的get_r1函数,以A1满足您的需要.

class A1: public AInterface
{
  public:
     boost::shared_ptr<RetInterface> get_r() const
     {
         return get_r1();
     }
     boost::shared_ptr<Ret1> get_r1() const {...}
     ...
};
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用访问者模式或类似我的Dynamic Double Dispatch技术将回调函数传递给返回的对象,然后可以使用正确的类型调用回调.

  • 在实现多个接口的类上使用clone方法返回指向派生类的指针. (5认同)

Bru*_*ams 6

这篇博客文章中发布了一个巧妙的解决方案(来自 Raoul Borges)

在添加对多重继承和抽象方法的支持之前,摘录如下:

template <typename Derived, typename Base>
class clone_inherit<Derived, Base> : public Base
{
public:
   std::unique_ptr<Derived> clone() const
   {
      return std::unique_ptr<Derived>(static_cast<Derived *>(this->clone_impl()));
   }
 
private:
   virtual clone_inherit * clone_impl() const override
   {
      return new Derived(*this);
   }
};

class concrete: public clone_inherit<concrete, cloneable>
{
};

int main()
{
   std::unique_ptr<concrete> c = std::make_unique<concrete>();
   std::unique_ptr<concrete> cc = c->clone();
 
   cloneable * p = c.get();
   std::unique_ptr<clonable> pp = p->clone();
}
Run Code Online (Sandbox Code Playgroud)

我鼓励阅读全文。它写得很简单并且解释得很好。