C++11 std::dynamic_pointer_cast行为咨询:类继承场景类型转换问题
刚好对这个场景很熟悉,我来给你详细讲清楚std::dynamic_pointer_cast在这里的具体行为,结合你的类结构来拆解:
核心前提:确保类层次是多态的
首先你得给基类I添加至少一个虚函数(最常用的就是虚析构函数),否则dynamic_pointer_cast根本无法工作——因为它依赖运行时类型信息(RTTI)来判断类型是否匹配,而只有多态类才会生成RTTI信息。修改你的I类:
class I { public: virtual ~I() = default; // 必须加虚析构,同时满足多态要求 };
另外,虚析构还能避免用std::shared_ptr<I>销毁派生类对象时的内存泄漏问题,这个是刚需。
转换成功的场景
当你的std::shared_ptr<I>实际指向的是B或者B的派生类对象时(比如你代码里的auto p = std::shared_ptr<I>(new B(data));),调用std::dynamic_pointer_cast<B>(p)会返回一个有效的std::shared_ptr<B>:
- 这个新的智能指针和原
p共享同一个对象的所有权,所以对象的引用计数会增加1; - 你可以安全地通过它调用
B类的成员(比如getDataB())或者访问B_成员变量。
示例代码:
auto p = std::shared_ptr<I>(new B(data)); // 尝试转换为B类型的shared_ptr if (auto pb = std::dynamic_pointer_cast<B>(p)) { // 转换成功,放心使用 auto b_data = pb->getDataB(); auto b_member = pb->B_; }
转换失败的场景
如果p指向的对象不是B或其派生类(比如指向A对象,或者直接指向I对象),std::dynamic_pointer_cast<B>(p)会返回一个空的std::shared_ptr<B>(也就是pb.get() == nullptr)。
这种情况下你可以通过判断指针是否为空,来避免非法访问派生类成员的风险:
auto p = std::shared_ptr<I>(new A()); auto pb = std::dynamic_pointer_cast<B>(p); if (!pb) { // 转换失败,不要访问pb的成员 std::cout << "转换到B类型失败" << std::endl; }
几个额外的关键点
- 和
std::static_pointer_cast的区别:static_pointer_cast不会做运行时类型检查,哪怕转换逻辑不安全(比如把指向A的I指针转成B),它也会返回非空指针,后续访问会导致未定义行为。所以在这种需要动态判断类型的场景下,一定要用dynamic_pointer_cast。 - 引用计数的关联:转换成功后,原
shared_ptr<I>和新的shared_ptr<B>的引用计数是绑定的,只有当所有指向该对象的智能指针都被销毁时,对象才会被正确释放。
内容的提问来源于stack exchange,提问作者Flo Win
相关产品推荐
相关产品推荐

