我有这样的代码:

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

这种代码不编译。

在visual studio它提出了

C2555:压倒一切的虚拟功能返回的类型不同于和不是 协变

如果我不用 boost::shared_ptr 但是,返回原指针,代码汇编(我理解这是由于 协变回归类型 在C++)。我可以看到的问题是因为 boost::shared_ptrRet1 不是来自 boost::shared_ptrRetInterface.但我想回到 boost::shared_ptrRet1 用于其他类别的,我必须投返回的价值之后返回。

  1. 我做错了什么?
  2. 如果不是,为什么语言,这样的-应该扩展到处理之间的转换的明智的指针,在这种情况?是有一个理想的解决方法?
有帮助吗?

解决方案

首先,这的确是它是如何工作在C++:回归类型的虚拟功能衍生出类必须同在基类。没有特别例外的一个函数,返回基准/指向某些类X可以复盖一个函数,返回基准/指针一类是来自X,但是作为你的注意,这并不允许 聪明的 指针(例如 shared_ptr),只是普通的指针。

如果你接口 RetInterface 是足够全面,那么你不需要知道实际返回的类型在调用代码。总的来说没有意义无论如何:的原因 get_r 是一个 virtual 功能放在第一位是因为你会叫它通过一个指或者参照的基类 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 {...}
     ...
};

或者,可以利用访问的模式或类似的东西我的 动态双派 技术来传递一个回在返回的物体,然后可以调用回调,用正确类型。

其他提示

这是什么解决方案:

template<typename Derived, typename Base>
class SharedCovariant : public shared_ptr<Base>
{
public:

typedef Base BaseOf;

SharedCovariant(shared_ptr<Base> & container) :
    shared_ptr<Base>(container)
{
}

shared_ptr<Derived> operator ->()
{
    return boost::dynamic_pointer_cast<Derived>(*this);
}
};

e.g:

struct A {};

struct B : A {};

struct Test
{
    shared_ptr<A> get() {return a_; }

    shared_ptr<A> a_;
};

typedef SharedCovariant<B,A> SharedBFromA;

struct TestDerived : Test
{
    SharedBFromA get() { return a_; }
};

你不能改变返回的类型(非指针,非基准的回报类型)当超载方法在C++。 A1::get_r 必须返回 boost::shared_ptr<RetInterface>.

安东尼*威廉姆斯有一个很好的全面的 答案.

这里是我的尝试:

template<class T>
class Child : public T
{
public:
    typedef T Parent;
};

template<typename _T>
class has_parent
{
private:
    typedef char                        One;
    typedef struct { char array[2]; }   Two;

    template<typename _C>
    static One test(typename _C::Parent *);
    template<typename _C>
    static Two test(...);

public:
    enum { value = (sizeof(test<_T>(nullptr)) == sizeof(One)) };
};

class A
{
public :
   virtual void print() = 0;
};

class B : public Child<A>
{
public:
   void print() override
   {
       printf("toto \n");
   }
};

template<class T, bool hasParent = has_parent<T>::value>
class ICovariantSharedPtr;

template<class T>
class ICovariantSharedPtr<T, true> : public ICovariantSharedPtr<typename T::Parent>
{
public:
   T * get() override = 0;
};

template<class T>
class ICovariantSharedPtr<T, false>
{
public:
    virtual T * get() = 0;
};

template<class T>
class CovariantSharedPtr : public ICovariantSharedPtr<T>
{
public:
    CovariantSharedPtr(){}

    CovariantSharedPtr(std::shared_ptr<T> a_ptr) : m_ptr(std::move(a_ptr)){}

    T * get() final
   {
        return m_ptr.get();
   }
private:
    std::shared_ptr<T> m_ptr;
};

和一个小小的例子:

class UseA
{
public:
    virtual ICovariantSharedPtr<A> & GetPtr() = 0;
};

class UseB : public UseA
{
public:
    CovariantSharedPtr<B> & GetPtr() final
    {
        return m_ptrB;
    }
private:
    CovariantSharedPtr<B> m_ptrB = std::make_shared<B>();
};

int _tmain(int argc, _TCHAR* argv[])
{
    UseB b;
    UseA & a = b;
    a.GetPtr().get()->print();
}

说明:

这个方案意味着元progamming和修改课程中使用的共变聪明的指针。

简单模板结构 Child 是在这里结合的类型 Parent 和继承权。任何类继承 Child<T> 会继承 T 和定义 T 作为 Parent.课程中使用的共变聪明指针需要这种类型加以定义。

has_parent 是用来检测在编制时间,如果一类定义的类型 Parent 或者不是。这部分是不是我的,我用同样的代码,作为检测,如果一方法存在(看看这里)

因为我们想要的协用智能指针,我们希望我们能指针,以模仿的现有的阶级结构。很容易解释它是如何工作的例子。

当一个 CovariantSharedPtr<B> 定义,它继承了 ICovariantSharedPtr<B>, ,这被解释为 ICovariantSharedPtr<B, has_parent<B>::value>.作为 B 继承 Child<A>, has_parent<B>::value 是真的,所以 ICovariantSharedPtr<B>ICovariantSharedPtr<B, true> 和继承 ICovariantSharedPtr<B::Parent> 这是 ICovariantSharedPtr<A>.作为 A 有没有 Parent 定义, has_parent<A>::value 是假的, ICovariantSharedPtr<A>ICovariantSharedPtr<A, false> 和继承什么。

主要的一点是因为 B继承 A, 我们有 ICovariantSharedPtr<B>继承 ICovariantSharedPtr<A>.所以任何方法返回的指针或一个参考上 ICovariantSharedPtr<A> 可以重载的方法返回同一个月 ICovariantSharedPtr<B>.

有一个整洁的解决方案张贴在 这篇文章 (从拉乌尔*博尔赫斯)

摘录的位之前加入支持多个继承和抽象的方法是:

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 = b->clone();

   cloneable * p = c.get();
   std::unique_ptr<clonable> pp = p->clone();
}

我会鼓励阅读全文。它只是书面的,很好的解释。

先生Fooz 答复第1部分的问题。第2部分,它以这种方式工作,因为编译器不知道,如果它将要求相::get_r或A1::get_r在编制时间-这需要知道什么样的回报价值,它要得到的,所以它坚持这两种方法返回同一类型。这是一部分C++的规范。

为解决方法,如果A1::get_r返回指RetInterface,虚拟方法在RetInterface将仍然作为预期和适当的对象将被删除时的指针被摧毁。有没有需要不同的回报类型。

也许你可以使用一个参数得到解"协返回的提高shared_ptrs.

 void get_r_to(boost::shared_ptr<RetInterface>& ) ...

因为我怀疑一个呼叫者可以放在一个更精致的情况类型的论点。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top