一 C++11前
在C++11之前,对智能指针转换的方法大概如下:
std::shared_ptr<T>(static_cast<T*>(r.get()))
std::shared_ptr<T>(dynamic_cast<T*>(r.get()))
std::shared_ptr<T>(const_cast<T*>(r.get()))
但它们有可能导致未定义行为,即删除同一对象两次。
二 C++11
C++11开始引入了std::static_pointer_cast,std::dynamic_pointer_cast,std::const_pointer_cast。(std::reinterpret_pointer_cast在C++17中引入)。头文件为<memory>,申明如下:
template< class T, class U >
std::shared_ptr<T> static_pointer_cast( const std::shared_ptr<U>& r ) noexcept; (1)(C++11 起)
template< class T, class U >
std::shared_ptr<T> static_pointer_cast( std::shared_ptr<U>&& r ) noexcept; (2)(C++20 起)
template< class T, class U >
std::shared_ptr<T> dynamic_pointer_cast( const std::shared_ptr<U>& r ) noexcept; (3)(C++11 起)
template< class T, class U >
std::shared_ptr<T> dynamic_pointer_cast( std::shared_ptr<U>&& r ) noexcept; (4)(C++20 起)
template< class T, class U >
std::shared_ptr<T> const_pointer_cast( const std::shared_ptr<U>& r ) noexcept; (5)(C++11 起)
template< class T, class U >
std::shared_ptr<T> const_pointer_cast( std::shared_ptr<U>&& r ) noexcept; (6)(C++20 起)
template< class T, class U >
std::shared_ptr<T> reinterpret_pointer_cast( const std::shared_ptr<U>& r ) noexcept; (7)(C++17 起)
template< class T, class U >
std::shared_ptr<T> reinterpret_pointer_cast( std::shared_ptr<U>&& r ) noexcept; (8)(C++20 起)
特别是C++20中引入的右值引入版本,除了(4)若dynamic_cast失败不会更改r,(2)(6)(8)调用后,r为空且r.get() == nullptr
三 举例
#include <iostream>
#include <memory>
struct Base
{
int a;
virtual void f() const { std::cout << "I am base!\n";}
virtual ~Base(){}
};
struct Derived : Base
{
void f() const override
{ std::cout << "I am derived!\n"; }
~Derived(){}
};
int main(){
auto basePtr = std::make_shared<Base>();
std::cout << "Base pointer says: ";
basePtr->f();
auto derivedPtr = std::make_shared<Derived>();
std::cout << "Derived pointer says: ";
derivedPtr->f();
// static_pointer_cast to go up class hierarchy
basePtr = std::static_pointer_cast<Base>(derivedPtr);
std::cout << "Base pointer to derived says: ";
basePtr->f();
// dynamic_pointer_cast to go down/across class hierarchy
auto downcastedPtr = std::dynamic_pointer_cast<Derived>(basePtr);
if(downcastedPtr)
{
std::cout << "Downcasted pointer says: ";
downcastedPtr->f();
}
// All pointers to derived share ownership
std::cout << "Pointers to underlying derived: "
<< derivedPtr.use_count()
<< "\n";
}
结果:
四 参考