簡體   English   中英

具有智能指針的返回類型協方差

[英]Return Type Covariance with Smart Pointers

在C ++中,我們可以這樣做:

struct Base
{
   virtual Base* Clone() const { ... }
   virtual ~Base(){}
};

struct Derived : Base
{
   virtual Derived* Clone() const {...} //overrides Base::Clone
};

但是,以下方法不會起到相同的作用:

struct Base
{
   virtual shared_ptr<Base> Clone() const { ... }
   virtual ~Base(){}
};

struct Derived : Base
{
   virtual shared_ptr<Derived> Clone() const {...} //hides Base::Clone
};

在此示例中, Derived::Clone 隱藏 Base::Clone而不是覆蓋它,因為標准指出,重寫成員的返回類型只能從引用(或指針)到基址再到引用(或指針)再到派生。 有什么聰明的解決方法嗎? 當然,有人可能會爭辯說Clone函數無論如何都應該返回一個普通的指針,但是讓我們暫時忘記它-這只是一個示例。 我正在尋找一種方法,可以將虛擬函數的返回類型從從智能指針到Base更改為智能指針到Derived

提前致謝!

更新:感謝Iammilind ,我的第二個示例確實無法編譯

您不能直接做到這一點,但是在非虛擬接口習慣用法的幫助下,有兩種方法可以對其進行仿真。

對原始指針使用協方差,然后包裝它們

struct Base
{
private:
   virtual Base* doClone() const { ... }

public:
   shared_ptr<Base> Clone() const { return shared_ptr<Base>(doClone()); }

   virtual ~Base(){}
};

struct Derived : Base
{
private:
   virtual Derived* doClone() const { ... }

public:
   shared_ptr<Derived> Clone() const { return shared_ptr<Derived>(doClone()); }
};

僅當您實際上有原始指針開始時,此方法才有效。

通過投射模擬協方差

struct Base
{
private:
   virtual shared_ptr<Base> doClone() const { ... }

public:
   shared_ptr<Base> Clone() const { return doClone(); }

   virtual ~Base(){}
};

struct Derived : Base
{
private:
   virtual shared_ptr<Base> doClone() const { ... }

public:
   shared_ptr<Derived> Clone() const
      { return static_pointer_cast<Derived>(doClone()); }
};

在這里,您必須確保Derived::doClone所有替代實際上都返回指向Derived或從其Derived的類的指針。

@ymett使用CRTP技術改善了一個很好的答案 這樣,您不必擔心忘記在派生對象中添加非虛擬函數。

struct Base
{
private:
   virtual Base* doClone() const { ... }

public:
   shared_ptr<Base> Clone() const { return shared_ptr<Base>(doClone()); }

   virtual ~Base(){}
};

template<class T>
struct CRTP_Base : Base
{
public:
   shared_ptr<T> Clone() const { return shared_ptr<T>(doClone()); }
};

struct Derived : public CRTP_Base<Derived>
{
private:
   virtual Derived* doClone() const { ... }
};

在此示例Derived::Clone隱藏Base::Clone而不是覆蓋它

,它不會隱藏它。 實際上,這是一個編譯錯誤

您不能使用僅在返回類型上有所不同的另一個函數來覆蓋或隱藏虛擬函數。 因此返回類型應該相同或協變 ,否則程序是非法的,因此會出錯。

因此,這意味着沒有其他方法可以將shared_ptr<D>轉換為shared_ptr<B> 唯一的方法是擁有B*D*關系(您已經在問題中排除了這種關系)。

我想到了一些主意。 首先,如果可以使用第一個版本,則只需保留該Clone即可, 然后編寫另一個受保護的_clone ,該_clone實際上返回派生的指針。 兩個Clone都可以使用它。

這就引出了一個問題,為什么要這樣呢? 另一種方法是強制(外部)函數,在該函數中,您會收到一個shared_ptr<Base>並且可以將其強制到shared_ptr<Derived> 也許是這樣的:

template <typename B, typename D>
shared_ptr<D> coerce(shared_ptr<B>& sb) throw (cannot_coerce)
{
// ...
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM