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


访问者模式用于分离稳定的数据结构与易变的操作,通过双分派实现开闭原则;核心角色为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  # 异步  # 遍历  # 需注意  # 这是  # 若需  # 开闭  # 都要  # 也能  # 两次 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 网络优化76771 】 【 技术知识130152 】 【 IDC云计算60162 】 【 营销推广131313 】 【 AI优化88182 】 【 百度推广37138 】 【 网站推荐60173 】 【 精选阅读31334


相关推荐: php查询数据怎么分组_groupby分组查询配合聚合函数【技巧】  如何在Golang中捕获HTTP服务器错误_GolangHTTP Handler中error处理  如何在Golang中实现邮件发送功能_Golang SMTP发送与错误处理示例  Win11怎么解压RAR文件 Win11自带解压功能使用方法  Win11怎么开启远程桌面连接_Windows11系统属性远程设置  Win11搜索不到蓝牙耳机怎么办 Win11蓝牙驱动更新修复【详解】  如何用正则与预处理高效拦截带干扰符的恶意域名  微信JSAPI支付回调PHP怎么接收_处理JSAPI异步通知数据方法【指南】  PythonWeb前后端整合项目教程_FastAPIReact完整实例  Win11怎么设置默认视频播放器_Windows 11关联媒体文件打开方式【步骤】  MAC的“接续互通”功能无法使用怎么办_MAC检查蓝牙、Wi-Fi和相同Apple ID登录  Win11怎么设置鼠标宏_Win11鼠标按键自定义编程教程【详解】  Windows11怎么用“记事本”自动换行与编码 Windows11记事本启用自动换行选择UTF-8编码避免乱码兼容多语言【教程】  如何使用Golang进行HTTP服务性能测试_测量吞吐量和延迟  Win11怎么关闭通知中心_Windows11系统通知与专注助手设置  短链接怎么用php递归还原_多层加密链接的处理法【详解】  Windows10系统怎么查看运行时间_Win10 CPU正常运行时间查询  电脑无法识别U盘怎么办 Windows磁盘管理与驱动更新修复识别问题【解决】  PyTorch DDP 多进程训练在 Kaggle 笔记本中的正确启动方式  php8.4新语法match怎么用_php8.4match表达式替代switch【方法】  Win10如何设置双wan路由器 Win10双wan路由器设置方法【指南】  Windows如何拦截腾讯视频广告_Windows拦截腾讯视频广告方法【方法】  Linux如何申请SSL免费证书_Linux下Certbot安装与Nginx自动续期【指南】  c++中如何使用虚函数实现多态_c++多态性实现原理  如何使用Golang写入二进制文件_Golang io Write二进制写入示例  Windows10如何彻底关闭自动更新_Win10服务与组策略双重禁用  win11如何清理传递优化文件 Win11为C盘瘦身删除更新缓存【技巧】  Python路径拼接规范_跨平台处理说明【指导】  如何在JavaScript中动态拼接PHP的base_url与JS变量  c++20的std::format怎么用 比printf更安全高效的格式化方法【详解】  如何开启Windows的远程服务器管理工具(RSAT)?(管理服务器)  c# await 一个已经完成的Task会发生什么  Windows 10怎么把任务栏放在屏幕上方_Windows 10解锁任务栏并拖动位置  MAC如何设置网卡MAC地址克隆_MAC终端修改物理地址与环境模拟【教程】  Win11怎么设置默认输入法 Win11固定中文输入法【步骤】  XSLT怎么生成动态的HTML属性名和标签名  win11 OneDrive怎么彻底关闭 Win11禁用并卸载OneDrive教程【分享】  Windows服务启动类型恢复方法_错误修改导致的系统服务异常  LINUX的SELinux是什么_详解LINUX强制访问控制系统的入门与配置  Win10怎么限制单程序CPU占用上限_Win10任务管理器亲和性或第三方工具均衡负载【技巧】  Win10如何更改开机密码_Windows10登录选项更改密码  Win11任务栏怎么调到左边_Win11开始菜单居左设置教程【步骤】  如何使用Golang sync.Map实现并发安全map_避免锁竞争  php在Linux怎么部署_LNMP环境搭建PHP服务的详细指南【指南】  Python生成器表达式内存优化_惰性计算说明【指导】  Linux怎么查找死循环进程_Linux系统负载分析与进程彻底结束【教程】  C++如何编写函数模板?(泛型编程入门)  零基础学会Python自动化办公_高效处理Excel与PDF文档  Win11无法识别耳机怎么办_解决Win11插耳机没声音问题【步骤】  php485返回数据不完整怎么办_php485数据分包重组处理方法【教程】 

 2025-12-26

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

致胜网络推广营销网


致胜网络推广营销网

致胜网络推广营销网专注海外推广十年,是谷歌推广.Facebook广告全球合作伙伴,我们精英化的技术团队为企业提供谷歌海外推广+外贸网站建设+网站维护运营+Google SEO优化+社交营销为您提供一站式海外营销服务。

 915688610

 17370845950

 915688610@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.