c++如何实现一个访问者模式_c++行为型设计模式Visitor【详解】

9次阅读

访问者模式用于分离稳定的数据结构与易变的操作,通过双分派实现开闭原则;核心角色为 Visitor(定义 visit 重载)、Element(实现 accept)和 ObjectStructure(遍历元素);需注意 const 正确性与新增类型对 Visitor 的侵入性。

c++ 如何实现一个访问者模式_c++ 行为型设计模式 Visitor【详解】

访问者模式(Visitor Pattern)在 C++ 中主要用于分离数据结构与作用于其上的操作,特别适合当对象结构稳定但操作频繁变化的场景。它通过双分派机制,让新增操作无需修改现有类,符合开闭原则。

核心结构:Visitor、Element、ObjectStructure

Visitor 模式包含三个关键角色:

  • Visitor(访问者):定义一组 visit() 重载函数,每个对应一种 Element 类型;通常抽象为基类,支持扩展不同行为(如打印、序列化、统计)。
  • Element(元素):定义 accept(Visitor&) 接口,负责将自身 this 指针传给访问者;每个具体 Element(如 Circle、Rectangle)实现 accept,调用 visitor.visit(*this)。
  • ObjectStructure(对象结构):如容器(vectorred_ptr>),提供遍历接口(如 traverse(Visitor&)),依次对每个元素调用 accept。

关键实现细节:双分派与 const 正确性

C++ 不原生支持双分派,访问者模式靠两次虚函数调用模拟:第一次是 Element::accept() 的虚调用(确定元素类型),第二次是 Visitor::visit(ElementType&) 的重载解析(确定操作类型)。需注意:

  • visit 函数参数应为 const ElementType&,避免意外修改;若需修改,可额外提供非 const 重载。
  • accept 函数一般声明为 virtual void accept(Visitor&) const,保证 const 对象也能被访问。
  • 为支持 const 和非 const 访问者,可将 Visitor 设计为模板或拆分为 ConstVisitor / MutableVisitor。

简易代码示例(带智能指针与多态)

(省略头文件和命名空间)

Visitor 基类:

立即学习 C++ 免费学习笔记(深入)”;

struct Visitor {virtual void visit(const Circle&) = 0;     virtual void visit(const Rectangle&) = 0;     virtual ~Visitor() = default;};

Element 基类及实现:

struct Element {virtual void accept(Visitor&) const = 0;     virtual ~Element() = default;};  struct Circle : Element {double r;     void accept(Visitor& v) const override {v.visit(*this); } };  struct Rectangle : Element {double w, h;     void accept(Visitor& v) const override {v.visit(*this); } };

具体访问者与使用:

struct PrintVisitor : Visitor {void visit(const Circle& c) const override {cout << "Circle(r=" << c.r << ")"; }     void visit(const Rectangle& r) const override {cout << "Rect(w=" << r.w << ",h=" << r.h << ")"; } };  // 使用 vector> shapes = {make_shared(Circle{2.0}), make_shared(Rectangle{3.0,4.0})}; PrintVisitor printer; for (const auto& e : shapes) e->accept(printer);

适用场景与注意事项

适合结构稳定(如 AST、GUI 控件树、几何图元集合)、操作多变(渲染、导出、校验、优化)的情况。但要注意:

  • 每次新增 Element 类型,所有 Visitor 子类都要补 visit() 函数——这是访问者模式的典型权衡(操作易扩展,结构难扩展)。
  • 避免在 visit 中做耗时操作;若需异步或缓存,建议 Visitor 内部封装状态。
  • 现代 C++ 可结合 std::variant + std::visit 实现类似效果(更轻量),但失去运行时动态添加访问者的能力。

基本上就这些。用好访问者,关键在想清楚“谁变谁不变”——结构不变、行为常变时,它很踏实。

星耀云
版权声明:本站原创文章,由 星耀云 2025-12-26发表,共计1369字。
转载说明:转载本网站任何内容,请按照转载方式正确书写本站原文地址。本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。
text=ZqhQzanResources