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

发布时间 - 2025-12-26 00:00:00    点击率:
访问者模式用于分离稳定的数据结构与易变的操作,通过双分派实现开闭原则;核心角色为Visitor(定义visit重载)、Element(实现accept)和ObjectStructure(遍历元素);需注意const正确性与新增类型对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 基类:

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 实现类似效果(更轻量),但失去运行时动态添加访问者的能力。

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


# c++  # red  # 命名空间  # 封装  # 多态  # 子类  # const  # void  # 指针  # 数据结构  # 重载函数  # 虚函数  # 接口  # 对象  # this  # 异步  # 遍历  # 需注意  # 这是  # 若需  # 开闭  # 都要  # 也能  # 两次 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 教学论文网站制作软件有哪些,写论文用什么软件 ?  怎么制作一个起泡网,水泡粪全漏粪育肥舍冬季氨气超过25ppm,可以有哪些措施降低舍内氨气水平?  Laravel怎么使用artisan命令缓存配置和视图  html5audio标签播放结束怎么触发事件_onended回调方法【教程】  如何批量查询域名的建站时间记录?  html5怎么画眼睛_HT5用Canvas或SVG画眼球瞳孔加JS控制动态【绘制】  长沙做网站要多少钱,长沙国安网络怎么样?  Laravel如何自定义分页视图?(Pagination示例)  如何自定义safari浏览器工具栏?个性化设置safari浏览器界面教程【技巧】  laravel怎么配置Redis作为缓存驱动_laravel Redis缓存配置教程  如何在IIS7中新建站点?详细步骤解析  Mybatis 中的insertOrUpdate操作  香港服务器如何优化才能显著提升网站加载速度?  微信小程序 wx.uploadFile无法上传解决办法  Laravel API资源类怎么用_Laravel API Resource数据转换  制作企业网站建设方案,怎样建设一个公司网站?  详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)  Laravel如何从数据库删除数据_Laravel destroy和delete方法区别  深圳网站制作公司好吗,在深圳找工作哪个网站最好啊?  微信小程序 scroll-view组件实现列表页实例代码  PHP正则匹配日期和时间(时间戳转换)的实例代码  再谈Python中的字符串与字符编码(推荐)  Laravel怎么实现微信登录_Laravel Socialite第三方登录集成  弹幕视频网站制作教程下载,弹幕视频网站是什么意思?  Swift中swift中的switch 语句  Laravel如何处理文件上传_Laravel Storage门面实现文件存储与管理  Win11怎么设置默认图片查看器_Windows11照片应用关联设置  Linux后台任务运行方法_nohup与&使用技巧【技巧】  高性能网站服务器配置指南:安全稳定与高效建站核心方案  Laravel如何安装使用Debugbar工具栏_Laravel性能调试与SQL监控插件【步骤】  Laravel怎么实现一对多关联查询_Laravel Eloquent模型关系定义与预加载【实战】  Laravel如何创建自定义Facades?(详细步骤)  Linux安全能力提升路径_长期防护思维说明【指导】  Laravel如何发送系统通知?(Notification渠道示例)  如何快速搭建二级域名独立网站?  Laravel怎么实现搜索高亮功能_Laravel结合Scout与Algolia全文检索【实战】  北京企业网站设计制作公司,北京铁路集团官方网站?  Laravel如何实现多表关联模型定义_Laravel多对多关系及中间表数据存取【方法】  如何在 Telegram Web View(iOS)中防止键盘遮挡底部输入框  Laravel如何实现全文搜索_Laravel Scout集成Algolia或Meilisearch教程  晋江文学城电脑版官网 晋江文学城网页版直接进入  郑州企业网站制作公司,郑州招聘网站有哪些?  如何快速上传自定义模板至建站之星?  今日头条AI怎样推荐抢票工具_今日头条AI抢票工具推荐算法与筛选【技巧】  Java Adapter 适配器模式(类适配器,对象适配器)优缺点对比  如何在云主机快速搭建网站站点?  如何在腾讯云免费申请建站?  如何挑选最适合建站的高性能VPS主机?  如何在橙子建站中快速调整背景颜色?  html5的keygen标签为什么废弃_替代方案说明【解答】