C++基类数组存储子类实例时如何调用继承类draw方法
问题根因
你的代码跑不通有三个核心问题:
- 对象切片:数组元素类型是基类
Panel,存入派生类实例时,派生类独有的成员(虚表、子类方法、自定义成员)会被直接截断,数组里存储的是纯基类对象,和原来的子类实例没有关系。 - 多态未生效:基类没有定义
draw虚函数,编译器编译阶段就会尝试在Panel类里找draw方法,找不到必然报错。 - 隐式编译错误:两个子类的构造函数没有加
public修饰,class默认访问权限是私有,外部根本无法构造子类实例。
修正实现
第一步:改造基类,启用多态
基类定义纯虚draw方法,同时加虚析构保证多态场景下资源释放正确:
class Panel { public: const char* name; int id; Panel(const char* name, int id) : name(name), id(id) { } // 纯虚函数,所有子类必须实现draw逻辑 virtual void draw() = 0; // 虚析构,避免基类指针释放子类对象时内存泄漏 virtual ~Panel() = default; };
第二步:子类重写draw方法
子类重写虚函数时加override关键字,编译器会自动校验重写签名是否正确,避免写错参数、const属性导致重写失效,同时把构造函数设为公有:
class SpecialPanel1 : public Panel { public: SpecialPanel1(const char* name, int id) : Panel(name, id) { } void draw() override { // 面板1绘制逻辑 } }; class SpecialPanel2 : public Panel { public: SpecialPanel2(const char* name, int id) : Panel(name, id) { } void draw() override { // 面板2绘制逻辑 } };
第三步:数组存储基类指针,避免对象切片
不要直接存基类对象,存基类指针(推荐用智能指针自动管理内存,避免手动new/delete的泄漏问题):
#include <memory> int main() { int visiblePanel_id = 1; // 存基类智能指针的数组,不会触发对象切片 std::unique_ptr<Panel> panels[2] = { std::make_unique<SpecialPanel1>("", 1), std::make_unique<SpecialPanel2>("", 2), }; // 遍历用右值引用接收,避免不必要的拷贝 for (auto&& p : panels) { if (p->id == visiblePanel_id) { p->draw(); break; // 找到目标面板直接退出循环,不用遍历剩余项 } } return 0; }
可选优化
如果面板数量较多,每次遍历数组找ID效率太低,可以改用哈希表存ID到面板的映射,查找时间复杂度从O(n)降到O(1):
#include <unordered_map> #include <memory> int main() { int visiblePanel_id = 1; std::unordered_map<int, std::unique_ptr<Panel>> panel_map; panel_map.emplace(1, std::make_unique<SpecialPanel1>("", 1)); panel_map.emplace(2, std::make_unique<SpecialPanel2>("", 2)); // 直接根据ID查找面板,无需遍历 if (auto it = panel_map.find(visiblePanel_id); it != panel_map.end()) { it->second->draw(); } return 0; }
内容的提问来源于stack exchange,提问作者sta
相关产品推荐
相关产品推荐

