如何通过抽象类智能指针访问子类的受保护成员变量?
解决方案:通过抽象基类智能指针访问子类专属成员
要通过unique_ptr<Writer>访问youngWriter中的pencil成员,核心问题是基类Writer没有定义getPencil方法,直接调用会编译失败。这里提供两种可行方案:
方案一:使用dynamic_cast向下转型
dynamic_cast可以在运行时检查类型转换的合法性,只有当智能指针实际指向youngWriter对象时,转换才会成功。
修正后的完整代码示例
#include <memory> #include <string> class Pen{ public: Pen(std::string _color): color(_color){} // 修正构造函数名大小写,补充std::命名空间 std::string getColor(){return color;} // 补充返回类型 protected: std::string color; }; class Pencil{}; // 补充Pencil类定义 // 统一基类名大小写为Writer class Writer{ public: Writer() {} virtual void changeColor(std::string color) = 0; // 补充返回类型void }; class oldWriter: public Writer{ protected: Pen *pen; public: // 修正构造函数参数:传入Pen指针而非string oldWriter(Pen* _pen): pen(_pen){} virtual void changeColor(std::string color){ pen->color = color;} // 补充返回类型 }; class youngWriter: public Writer{ protected: Pen *pen; Pencil pencil; public: youngWriter(Pen* _pen): pen(_pen){} virtual void changeColor(std::string color){ pen->color = color;} Pencil& getPencil(){return pencil;} // 返回引用避免不必要拷贝 }; int main(){ // 创建youngWriter对象并赋值给基类智能指针 std::unique_ptr<Writer> artist = std::make_unique<youngWriter>(new Pen("blue")); // 用dynamic_cast向下转型,先获取裸指针判断 if (auto* young_artist = dynamic_cast<youngWriter*>(artist.get())) { Pencil& pencil = young_artist->getPencil(); // 在此操作pencil } else { // 转换失败,说明artist指向的不是youngWriter对象 } // 也可以直接转换智能指针 auto young_artist_ptr = std::dynamic_pointer_cast<youngWriter>(artist); if (young_artist_ptr) { Pencil& pencil = young_artist_ptr->getPencil(); // 操作pencil } }
注意事项
dynamic_cast要求基类包含至少一个虚函数(你的代码中Writer已有纯虚函数changeColor,满足要求)。- 转换后必须检查结果是否为空,避免空指针访问。
方案二:在基类添加虚方法
在Writer中定义一个返回Pencil指针的虚函数,子类按需重写,无需显式转型即可调用。
代码修改示例
class Writer{ public: Writer() {} virtual void changeColor(std::string color) = 0; // 添加默认返回nullptr的虚方法 virtual Pencil* getPencil() { return nullptr; } }; class youngWriter: public Writer{ // ... 其他代码不变 public: // 重写基类方法,返回自身pencil的地址 Pencil* getPencil() override { return &pencil; } }; int main(){ std::unique_ptr<Writer> artist = std::make_unique<youngWriter>(new Pen("blue")); Pencil* pencil = artist->getPencil(); if (pencil) { // 操作*pencil } }
优缺点
- 优点:代码更简洁,无需显式转型。
- 缺点:基类引入了子类专属的方法,可能破坏基类的抽象性,适合子类专属成员是通用业务场景的情况。
内容的提问来源于stack exchange,提问作者Amin mosayyebzadeh
相关产品推荐
相关产品推荐

