关于c ++:如何向下转换std :: shared_ptr?

How does one downcast a std::shared_ptr?

考虑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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(static_cast(ptr.get())),因为这样引用计数就不会在两个shared_ptr之间共享)


这应该起作用:

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


static_castshared_ptr等效项是static_pointer_castdynamic_castshared_ptr等效项是dynamic_pointer_cast


从C ++ 11开始,C ++标准的§20.10.2.2.9([util.smartptr.shared.cast])将std::shared_ptrstatic_castconst_castdynamic_cast等效项指定为如下:

std::static_pointer_cast

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

static_pointer_cast要求static_cast(r.get())的格式正确。如果r为空,则返回空的shared_ptr< T >,否则返回与r共享所有权的指针w,其中w.get() == static_cast(r.get())w.use_count() == r.use_count()

std::const_pointer_cast

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

const_pointer_caststatic_pointer_cast具有相似的要求和语义,不同之处在于,使用const_cast代替了static_cast

std::dynamic_pointer_cast

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

dynamic_pointer_cast有点不同,因为它要求dynamic_cast(r.get())格式正确并具有明确定义的语义。如果dynamic_cast(r.get())是非零值,则返回与r共享所有权的指针w,其中w.get() == dynamic_cast(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((U *) 0)格式正确并返回shared_ptr< T >(r, reinterpret_cast::element_type *>(r.get()))即可。注意N3920还更改了其他shared_ptr强制转换的措辞,并扩展了shared_ptr以支持数组。