You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++访问者模式是否支持对多个项目内的类执行访问操作?

关于你的初始判断

你的判断不准确。传统访问者模式完全可以支持跨项目访问不同节点类,核心是要把访问者抽象接口层和节点基类统一放在公共依赖组件中,而具体访问者实现放在上层业务项目中,不会出现循环依赖问题。

你现有代码的结构已经接近正确方案,唯一的问题是你把Visitor的具体实现放在了和Node、NodeA/NodeB同层的位置,才会出现依赖矛盾:如果Visitor的实现同时依赖NodeA和NodeB,放在公共层就会强制所有依赖公共层的项目都同时依赖ProjectA和ProjectB。

更优的解决方案

除了你提到的两种方案,还有三种更常用的低侵入实现方式,可根据项目技术栈选择:

1. 拆分公共抽象层方案(最推荐,符合经典访问者模式)

调整依赖结构即可完全解决跨项目问题,不需要修改现有节点类的核心逻辑:

  • 新增一个无额外依赖的公共基础项目Common,存放三个内容:Node基类定义、纯虚Visitor接口类(仅声明纯虚visit接口,不需要实现)、NodeA/NodeB的前向声明
  • ProjectA、ProjectB仅依赖Common,分别实现NodeA::accept和NodeB::accept,方法内部直接调用v.visit(*this)即可,不需要依赖其他项目
  • 具体的访问者实现放在同时依赖Common、ProjectA、ProjectB的上层业务项目中,继承Visitor基类实现所有visit方法,完全不需要修改ProjectA、ProjectB的现有代码

示例代码调整如下:

/// --- Common/Visitor.h 公共层头文件 ---
class Node;
class NodeA;
class NodeB;

class Visitor {
public:
    virtual ~Visitor() = default;
    virtual void visit(const Node&) = 0;
    virtual void visit(const NodeA&) = 0;
    virtual void visit(const NodeB&) = 0;
};
/// --- ProjectA/NodeA.cpp 仅依赖公共层 ---
#include "NodeA.h"
#include "Visitor.h"

void NodeA::accept(Visitor& v) {
    v.visit(*this);
}
/// --- 上层业务项目/MyConcreteVisitor.h 同时依赖三个项目 ---
#include "Visitor.h"
#include "NodeA.h"
#include "NodeB.h"

class MyConcreteVisitor : public Visitor {
public:
    void visit(const Node& node) override { /* 业务实现 */ }
    void visit(const NodeA& node) override { /* 业务实现 */ }
    void visit(const NodeB& node) override { /* 业务实现 */ }
};

2. 非循环访问者(Acyclic Visitor)模式

如果项目后续会频繁新增节点类型,不想每次新增节点都修改公共Visitor接口,可以用该变种模式:

  • 公共层仅存放空的Visitor基类,以及每个节点类型对应的独立访问接口(比如INodeAVisitor、INodeBVisitor)
  • 具体访问者需要访问哪种节点,就继承对应的访问接口,accept方法内通过动态类型转换判断访问者是否支持该节点的访问,不需要跨项目依赖
    缺点是存在运行时类型转换的开销,优点是完全解耦不同项目的节点和访问者。

3. std::variant + 访问器模式(C++17及以上推荐)

如果你的节点类不需要继承关系,或者可以改造成variant存储,直接用C++17标准库的std::visit实现访问者,完全不需要定义accept方法,也不会有跨项目依赖问题:

  • 定义using NodeVariant = std::variant<NodeA, NodeB, 其他节点类型>
  • 业务层实现访问器结构体,重载operator()处理不同的节点类型,直接调用std::visit(访问器实例, 节点变量)即可
    该方案是最简洁的,不需要继承也不需要虚函数,唯一要求是使用访问者的位置能拿到所有节点类型的定义。

内容的提问来源于stack exchange,提问作者Gábor Pálovics

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 01:30:03