C++中存储基类指针且可调用派生类函数的最优实现方案
C++ Cell类存储派生类指针优化方案
现有代码的问题
- 拼写错误:
std::dyanmic_pointer_cast应为std::dynamic_pointer_cast,类型判断中误用赋值符=代替比较符== - 手动维护
CellContentType枚举和实际指针类型的映射,容易出现不一致的bug,比如dynamic_pointer_cast转型失败时,枚举值仍被错误设置 - 运行时判断编译期即可确定的模板参数类型,存在冗余开销
- 成员变量公开,不符合封装原则
- main函数中需要手动判断类型再转型,代码冗余扩展性差,新增派生类时需要修改所有判断分支
最优实现方案
核心思路是利用C++面向对象的多态特性,通过虚函数表自动完成类型调度,完全避免手动类型判断。
方案1:基类定义统一虚接口(最常用,适合绝大多数场景)
在虚基类CellContent中定义所有派生类都需要实现的公共虚接口,调用时直接通过基类指针调用即可,不需要关心实际派生类型。
#include <memory> #include <iostream> // 虚基类 class CellContent { public: virtual ~CellContent() = default; // 虚基类必须声明虚析构函数 // 定义公共虚接口,示例为玩家踩中单元格的触发逻辑 virtual void onTrigger() = 0; }; class Enemy : public CellContent { public: void onTrigger() override { std::cout << "遭遇敌人,进入战斗\n"; } // Enemy专属方法 void attack() { std::cout << "敌人发动攻击\n"; } }; class Item : public CellContent { public: void onTrigger() override { std::cout << "拾取到道具\n"; } // Item专属方法 void use() { std::cout << "使用道具\n"; } }; class Cell { private: std::shared_ptr<CellContent> _cellContent; public: void setCellContent(std::shared_ptr<CellContent> content) { _cellContent = std::move(content); } CellContent* getCellContent() { return _cellContent.get(); } // 保留安全转型方法,供需要调用派生类专属方法的场景使用 template<typename T> std::shared_ptr<T> getCellContentAs() { return std::dynamic_pointer_cast<T>(_cellContent); } }; int main() { auto enemy = std::make_shared<Enemy>(); Cell cell; cell.setCellContent(enemy); // 直接调用虚接口,自动调度到对应派生类实现,无任何if分支 cell.getCellContent()->onTrigger(); return 0; }
方案2:访问者模式(适合需要对不同派生类执行大量专属逻辑的场景)
如果需要频繁调用派生类的专属方法,又不想到处写转型判断,可以用访问者模式将操作封装,彻底消除所有类型判断分支:
#include <memory> #include <iostream> // 派生类前向声明 class Enemy; class Item; // 访问者基类 class CellContentVisitor { public: virtual void visit(Enemy& enemy) = 0; virtual void visit(Item& item) = 0; }; class CellContent { public: virtual ~CellContent() = default; virtual void accept(CellContentVisitor& visitor) = 0; }; class Enemy : public CellContent { public: void accept(CellContentVisitor& visitor) override { visitor.visit(*this); } void attack() { std::cout << "敌人发动攻击\n"; } }; class Item : public CellContent { public: void accept(CellContentVisitor& visitor) override { visitor.visit(*this); } void use() { std::cout << "使用道具\n"; } }; class Cell { private: std::shared_ptr<CellContent> _cellContent; public: void setCellContent(std::shared_ptr<CellContent> content) { _cellContent = std::move(content); } CellContent* getCellContent() { return _cellContent.get(); } }; // 实现具体的交互访问者 class InteractVisitor : public CellContentVisitor { public: void visit(Enemy& enemy) override { enemy.attack(); } void visit(Item& item) override { item.use(); } }; int main() { auto enemy = std::make_shared<Enemy>(); Cell cell; cell.setCellContent(enemy); InteractVisitor visitor; // 自动调度到对应派生类的处理逻辑,无任何if分支 cell.getCellContent()->accept(visitor); return 0; }
优化优势
- 不需要手动维护类型枚举,完全避免类型不匹配的bug
- 新增派生类时只需要实现对应的虚接口/访问方法,不需要修改原有调用逻辑,符合开闭原则
- 代码更简洁,无冗余的类型判断分支
内容的提问来源于stack exchange,提问作者Ghorm
相关产品推荐
相关产品推荐

