如何向下转换std :: shared_ptr?


73

考虑:

struct SomethingThatsABase
{
    virtual bool IsChildOne() const { return false; }
    virtual bool IsChildTwo() const { return false; }
};

struct ChildOne : public SomethingThatsABase
{
    virtual bool IsChildOne() const { return true; }
};

struct ChildTwo : public SomethingThatsABase
{
    virtual bool IsChildTwo() const { return true; }
};

void SomeClientExpectingAChildOne(std::shared_ptr<ChildOne> const& ptrOne)
{
    //Does stuff
}

void SomeClient(std::shared_ptr<SomethingThatsABase> const& ptr)
{
    if (ptr->IsChildOne())
    {
        SomeClientExpectingAChildOne(ptr); //Oops.
        //Hmm.. can't static_cast here, because we need a `shared_ptr` out of it.
    }
}

(请注意,我不能简单地执行std::shared_ptr<ChildOne>(static_cast<ChildOne*>(ptr.get())),因为这样引用计数就不会在两个shared_ptrs之间共享)

Answers:


99

这应该起作用:

if (ptr->IsChildOne())
{
    SomeClientExpectingAChildOne(std::static_pointer_cast<ChildOne>(ptr));
}

1
完善!+1。(也许很快也会出现“绿色弯角物体”)
Billy ONeal

3
+1-我不知道std::static_pointer_cast!这是如何工作的,返回的shared_ptr行为是否像代理一样,使两个共享指针保持相同的引用计数?
Frerich Raabe 2011年

4
@Frerich:Ashared_ptr有两个指针-一个指向共享对象,另一个指向具有强引用计数和弱引用计数的块。shared_ptr不同类型的两个可以毫无困难地共享强和弱参考计数块。我的猜测是,它与实施static_pointer_cast是一个friendshared_ptr,当然你的实现可能会有所不同。
Billy ONeal

2
我一直shared_dynamic_cast在Boost中使用。dynamic_pointer_cast但是,显然它是更通用的,因为它可以与各种不同类型的指针(shared_ptr,原始指针intrusive_ptr,以及将来可能使用的其他任何指针)一起使用。
Tamas Demjen

@ FrerichRaabe,@ billy-oneal,可能它使用了aliasing constructor((ref,ptr)创建ref但指向的shared_pointer副本ptr
2013年

39

shared_ptr当量static_caststatic_pointer_cast,与shared_ptr等效的dynamic_castdynamic_pointer_cast


1
我没有意识到这两个方面,因此我去寻找一些文档。酷的东西!
格雷格·豪威尔

23

从C ++ 11开始,C ++标准的§20.10.2.2.9([util.smartptr.shared.cast])指定的等效项static_castconst_cast并且dynamic_castforstd::shared_ptr如下所示:

std::static_pointer_cast

template <class T, class U>
shared_ptr<T> static_pointer_cast(shared_ptr<U> const & r) noexcept;

static_pointer_cast需要结构static_cast<T *>(r.get())良好。如果r为空,shared_ptr<T>则返回空,否则返回wrwherew.get() == static_cast<T *>(r.get())和共享所有权的指针w.use_count() == r.use_count()

std::const_pointer_cast

template <class T, class U>
shared_ptr<T> const_pointer_cast(shared_ptr<U> const & r) noexcept;

const_pointer_cast具有与相似的要求和语义static_pointer_cast,只是const_cast使用代替static_cast

std::dynamic_pointer_cast

template <class T, class U>
shared_ptr<T> dynamic_pointer_cast(shared_ptr<U> const & r) noexcept;

dynamic_pointer_cast有点不同,因为它要求dynamic_cast<T *>(r.get())格式正确且语义明确。如果dynamic_cast<T *>(r.get())为非零值,则返回wrwherew.get() == dynamic_cast<T *>(r.get())和共享所有权的指针w.use_count() == r.use_count(),否则shared_ptr<T>返回空值。

std::reinterpret_pointer_cast

对于C ++ 17,N3920于2014年2月被纳入图书馆基础知识TS)也提出了std::reinterpret_pointer_cast与上述类似的方法,只要求reinterpret_cast<T *>((U *) 0)格式正确并返回即可shared_ptr<T>(r, reinterpret_cast<typename shared_ptr<T>::element_type *>(r.get()))。注意N3920还更改了其他shared_ptr强制转换的用语,并扩展shared_ptr为支持数组。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.