shared_ptr子类指针转换成父类指针
假设有如下应用场景:
class Base
{
public:
void addChild(std::shared_ptr<Base>& child)
{
...
}
}
class Derived : public Base
{}
int main()
{
Base a;
std::shared_ptr<Derived> b = std::make_shared<Derived>();
a.addChild(b); // Error
}
该代码中声明了两个类,Base类是基类,带有一个接受一个Base类型智能指针引用作为入参的成员函数addChild,而Derived类是Base类的派生类.
当我们在main函数中创建了一个Derived类的共享对象shared_ptr<Derived>时,不同于裸指针Derived*与Base*,它实际上与shared_ptr<Base>会被视作是不同的类型,因此Base类的成员函数addChild无法直接接受b的引用作为入参.那怎么办?
第一种解决方案也是最简单的一种解决方案是先把b转换成基类类型的智能指针.
int main()
{
Base a;
std::shared_ptr<Derived> b = std::make_shared<Derived>();
std::shared_ptr<Base> c = b; // convert to base class
a.addChild(c); // OK
}
还有一种解决方案, 我们可能会想到可以重新声明一个shared_ptr<Base>类型的智能指针,将它内部的指针指向Derived,这样就可以把它传给addChild函数了,但是对智能指针直接赋值肯定是不行的,因为shared_ptr内部有一个计数器,当计数器归零时它会delete内部真正的指针,把已经被一个智能指针管理的对象直接赋值给另一个智能指针会导致两个智能指针析构时重复delete对象,导致程序崩溃.
int main()
{
std::shared_ptr<Derived> b = std::make_shared<Derived>();
std::shared_ptr<Base> c = std::shared_ptr<Base>(b.get()); // Error
}
解决方案是让Base继承自shared_from_this
class Base : public std::shared_from_this<Base>
{
public:
void addChild(std::shared_ptr<Base>& child)
{
...
}
}
class Derived : public Base
{}
int main()
{
Base a;
std::shared_ptr<Derived> b = std::make_shared<Derived>();
std::shared_ptr<Base> c = std::make_shared<Base>(b->weak_from_this());
a.addChild(c); // OK
}
然后在需要传父类智能指针的地方使用std::make_shared<Base>(b->weak_from_this())将子类智能指针转换成父类智能指针,这样就可以顺利的把b指针保存的对象顺利传入addChild函数了.
当然,如果addChild函数内不需要保存shared_ptr的话,入参直接改成对Base对象的引用才是最好的解决方案.