C++多继承场景下如何安全将A类型智能指针转为B类型?
问题:如何在不逐一检查中间类的前提下,将抽象类A的实例安全转换为B类型?
假设存在抽象类A,仅当A的动态类型同时继承自B类时,才将其转换为B类类型。由于实际场景中存在大量中间类,有没有无需逐一检查这些中间类的可行方法?需要让以下C++代码正常运行:
#include <memory> #include <cassert> struct A { virtual void foo() = 0; }; struct B { virtual void bar() = 0; }; struct C : public A, public B { void foo() override {}; void bar() override {}; }; struct D : public A { void foo() override {}; }; int main() { std::shared_ptr<A> a_ptr_1 = std::make_shared<C>(); std::shared_ptr<A> a_ptr_2 = std::make_shared<D>(); std::shared_ptr<B> b_ptr_1 = /* do something to a_ptr_1 */ nullptr; std::shared_ptr<B> b_ptr_2 = /* do same thing to a_ptr_2 */ nullptr; assert(!b_ptr_2); assert(b_ptr_1); b_ptr_1->bar(); return 0; }
解决方案
直接用std::dynamic_pointer_cast就能解决,它是C++标准库专门为智能指针设计的动态类型转换工具,会在运行时自动检查对象的实际类型是否兼容,不需要手动枚举所有中间类。
修改后的main函数代码如下:
int main() { std::shared_ptr<A> a_ptr_1 = std::make_shared<C>(); std::shared_ptr<A> a_ptr_2 = std::make_shared<D>(); std::shared_ptr<B> b_ptr_1 = std::dynamic_pointer_cast<B>(a_ptr_1); std::shared_ptr<B> b_ptr_2 = std::dynamic_pointer_cast<B>(a_ptr_2); assert(!b_ptr_2); assert(b_ptr_1); b_ptr_1->bar(); return 0; }
原理说明:
std::dynamic_pointer_cast的作用和原生指针的dynamic_cast类似:如果被指向的对象的实际类型(动态类型)确实继承自目标类型(这里是B),就返回一个指向该对象的shared_ptr<B>,同时正确维护引用计数;- 如果对象的实际类型和B不兼容(比如D没有继承B),则返回空的
shared_ptr<B>,正好满足代码里assert(!b_ptr_2)的要求; - 这种方式完全不需要关心中间类的存在,只要对象的动态类型符合继承关系,就能自动完成转换。
补充:用原生指针的方式(不推荐)
如果不想用智能指针专用的转换函数,也可以先取出原始指针做dynamic_cast,再构造shared_ptr,但这种方式需要注意不要手动管理指针生命周期:
// 不推荐,因为容易出现指针生命周期管理问题 std::shared_ptr<B> b_ptr_1 = std::shared_ptr<B>(dynamic_cast<B*>(a_ptr_1.get())); std::shared_ptr<B> b_ptr_2 = std::shared_ptr<B>(dynamic_cast<B*>(a_ptr_2.get()));
这种方式虽然能工作,但shared_ptr会重新创建一个控制块,可能导致重复释放,所以优先用std::dynamic_pointer_cast。
内容的提问来源于stack exchange,提问作者ILutRf7
相关产品推荐
相关产品推荐

