如何通过指向父类的shared_ptr访问子类实例的成员字段?
问题原因
这个问题和shared_ptr本身没有关系,核心是C++的静态类型检查机制:
- 你声明的
shared_ptr<Foo>的静态类型是Foo,而Foo类定义中没有_b成员,编译期检查只会识别指针的静态类型,不会关心它实际指向的子类Bar实例,因此直接访问会报错。 - 直接声明
Bar bar(2)时,变量的静态类型就是Bar,编译器可以直接识别到Bar类的公开成员_b,所以可以正常访问。
解决方法
可以根据你的业务场景选择以下三种方案:
方案1:向下类型转换
如果你确定当前基类智能指针指向的就是Bar实例,可以用static_pointer_cast做转换,性能开销极低:
int main() { shared_ptr<Foo> bbar = make_shared<Bar>(3); auto bar_ptr = static_pointer_cast<Bar>(bbar); cout << bar_ptr->_b; return 0; }
如果不确定指向的类型,建议用dynamic_pointer_cast做安全转换,转换失败会返回空智能指针,注意使用dynamic_pointer_cast要求基类至少有一个虚函数,通常给基类加虚析构函数即可,同时也能避免继承场景下的内存泄漏问题:
struct Foo { virtual ~Foo() = default; }; // Bar类定义保持不变 int main() { shared_ptr<Foo> bbar = make_shared<Bar>(3); auto bar_ptr = dynamic_pointer_cast<Bar>(bbar); if (bar_ptr) { // 转换成功才访问,避免空指针异常 cout << bar_ptr->_b; } return 0; }
方案2:直接使用子类类型的智能指针
如果你一开始就明确创建的是Bar实例,不需要做基类向上转换,直接用shared_ptr<Bar>接收返回值即可:
int main() { shared_ptr<Bar> bbar = make_shared<Bar>(3); cout << bbar->_b; return 0; }
方案3:使用多态接口(推荐)
符合面向对象的多态设计规范,不需要手动做类型转换,封装性更好:
#include <memory> #include <iostream> using namespace std; struct Foo { virtual ~Foo() = default; // 基类定义虚接口 virtual int get_b() const = 0; }; class Bar : public Foo { public: Bar(int b) : _b(b) {}; // 子类实现接口 int get_b() const override { return _b; } private: const int _b; // 成员可改为私有,提升封装性 }; int main() { shared_ptr<Foo> bbar = make_shared<Bar>(3); cout << bbar->get_b(); return 0; }
内容的提问来源于stack exchange,提问作者user43283
相关产品推荐
相关产品推荐

