C++解释器开发:基于虚类运行时类型生成TypeChecked对象的问题
解决方案:利用虚函数工厂或访问者模式实现运行时类型匹配的模板实例化
你的核心问题在于模板类TypeChecked<T>的实例化是编译时确定的,但需要根据ValuableAST*的运行时实际类型创建对应实例。针对解释器AST的场景,有两种成熟的最佳实践:
方案一:虚工厂方法(Clone-with-Type)
给基类ValuableAST添加纯虚函数,让每个派生类负责创建自身对应的TypeChecked<T>实例,利用多态特性在运行时派发正确的创建逻辑。
步骤1:修改基类ValuableAST
添加虚函数clone_with_type,用于生成带类型标记的包装实例:
#include <memory> // 引入智能指针 class ValuableAST { public: virtual ~ValuableAST() = default; virtual bool is_checked() const { return false; } enum class ValueType { INTEGER, REAL }; virtual std::variant<int, double> value() const = 0; // 新增:返回带类型标记的包装实例,用智能指针避免内存泄漏 virtual std::unique_ptr<ValuableAST> clone_with_type(ValueType type) const = 0; };
步骤2:修改TypeChecked模板类
调整构造函数参数为const T*,避免不安全的const_cast:
template <class T> requires std::is_base_of_v<ValuableAST, T> class TypeChecked : public T { private: ValuableAST::ValueType type_; public: // 改为接受const T*,通过拷贝构造创建底层对象 explicit TypeChecked(ValuableAST::ValueType type, const T* value) : T(*value), type_(type) {} ValuableAST::ValueType type() const { return type_; } bool is_checked() const override { return true; } int get_int() const { if (type_ == ValuableAST::ValueType::INTEGER) { return std::get<int>(this->value()); } else { throw std::runtime_error("Type error"); } } double get_real() const { if (type_ == ValuableAST::ValueType::REAL) { return std::get<double>(this->value()); } else { throw std::runtime_error("Type error"); } } };
步骤3:在派生类中实现clone_with_type
以Number类为例:
class Number : public ValuableAST { private: std::variant<int, double> value_; public: std::variant<int, double> value() const { return value_; } explicit Number(int value) : value_(value) {} explicit Number(double value) : value_(value) {} explicit Number(const Number& number) : value_(number.value_) {} // 显式拷贝构造 // 实现虚工厂方法 std::unique_ptr<ValuableAST> clone_with_type(ValueType type) const override { return std::make_unique<TypeChecked<Number>>(type, this); } };
步骤4:在目标函数中使用
void function_accepting_valuable_ast(ValuableAST* ast, ValuableAST::ValueType checked_type) { // 生成带类型检查标记的实例 std::unique_ptr<ValuableAST> checked_ast = ast->clone_with_type(checked_type); // 使用checked_ast,无需手动delete,智能指针自动管理内存 if (checked_ast->is_checked()) { // 后续逻辑 } }
方案二:访问者模式(Visitor Pattern)
如果你的解释器需要对AST进行多种操作(如类型检查、代码生成、优化等),访问者模式更适合,它将操作逻辑与AST节点类型解耦。
步骤1:定义访问者接口
class ValuableASTVisitor { public: virtual ~ValuableASTVisitor() = default; virtual std::unique_ptr<ValuableAST> visit(const Number* node, ValuableAST::ValueType type) = 0; // 为其他派生类添加对应的visit方法 };
步骤2:实现TypeChecked创建者
class TypeCheckedCreator : public ValuableASTVisitor { public: std::unique_ptr<ValuableAST> visit(const Number* node, ValuableAST::ValueType type) override { return std::make_unique<TypeChecked<Number>>(type, node); } // 实现其他派生类的visit方法 };
步骤3:给基类添加accept方法
class ValuableAST { public: // ... 原有代码 ... virtual void accept(ValuableASTVisitor& visitor, ValuableAST::ValueType type, std::unique_ptr<ValuableAST>& result) const = 0; };
步骤4:派生类实现accept
class Number : public ValuableAST { // ... 原有代码 ... void accept(ValuableASTVisitor& visitor, ValuableAST::ValueType type, std::unique_ptr<ValuableAST>& result) const override { result = visitor.visit(this, type); } };
步骤5:在目标函数中使用
void function_accepting_valuable_ast(ValuableAST* ast, ValuableAST::ValueType checked_type) { TypeCheckedCreator creator; std::unique_ptr<ValuableAST> checked_ast; ast->accept(creator, checked_type, checked_ast); // 使用checked_ast }
方案对比与选择
- 虚工厂方法:代码简洁,实现成本低,适合派生类数量少、操作单一的场景,符合AST节点的职责单一原则。
- 访问者模式:扩展性强,新增操作无需修改AST节点类,适合需要对AST进行多种复杂处理的解释器/编译器场景。
- 无论哪种方案,都建议使用
std::unique_ptr或std::shared_ptr管理动态对象,避免手动内存管理带来的泄漏风险。
内容的提问来源于stack exchange,提问作者Junhui Zhu
相关产品推荐
相关产品推荐

