Ответ 1
Это должно работать:
if (ptr->IsChildOne())
{
SomeClientExpectingAChildOne(std::static_pointer_cast<ChildOne>(ptr));
}
Рассмотрим:
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_ptr
s)
Это должно работать:
if (ptr->IsChildOne())
{
SomeClientExpectingAChildOne(std::static_pointer_cast<ChildOne>(ptr));
}
эквивалент shared_ptr
static_cast
равен static_pointer_cast
, а эквивалент shared_ptr
dynamic_cast
равен dynamic_pointer_cast
.
Начиная с С++ 11, §20.10.2.2.9 ([util.smartptr.shared.cast]) стандарта С++ определяет эквиваленты static_cast
, const_cast
и dynamic_cast
для std::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>
, в противном случае возвращает указатель w
для совместного использования с r
, где w.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
, за исключением того, что вместо static_cast
используется const_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())
является ненулевым значением, возвращает указатель w
разделение собственности на r
где w.get() == dynamic_cast<T *>(r.get())
и w.use_count() == r.use_count()
, в противном случае возвращается пустой shared_ptr<T>
.
std::reinterpret_pointer_cast
:Для С++ 17, N3920 (принят в Основы библиотеки TS в феврале 2014 г.) также предложил a 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
для поддержки массивов.