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

C++ Visitor Pattern实现不同Visitor返回不同类型的解决方案咨询

解决方案

C++确实不允许虚函数声明为模板,我们可以用以下几种常用方案绕过这个限制:


方案1:返回值存储在Visitor实例中(兼容性最好,全C++版本支持)

不需要修改IVisitable的虚函数签名,将返回值存储在Visitor自身的成员变量里,accept统一返回void,调用完成后直接从Visitor实例提取结果即可。
代码示例:

// 非模板Visitor基类
class IVisitor {
public:
    virtual ~IVisitor() = default;
    virtual void visit(IVisitable& visitable) = 0;
};

class IVisitable {
public:
    virtual ~IVisitable() = default;
    virtual void accept(IVisitor& visitor) = 0;
};

// 模板派生Visitor层,封装对应类型的返回值存储逻辑
template<typename R>
class ResultVisitor : public IVisitor {
protected:
    R result_;
public:
    R get_result() const { return result_; }
};

// 返回int的具体Visitor
class ConcreteVisitorOne : public ResultVisitor<int> {
public:
    void visit(IVisitable& visitable) override {
        // 你的业务计算逻辑
        result_ = 123;
    }
};

// 返回bool的具体Visitor
class ConcreteVisitorTwo : public ResultVisitor<bool> {
public:
    void visit(IVisitable& visitable) override {
        // 你的业务计算逻辑
        result_ = true;
    }
};

class ConcreteVisitable : public IVisitable {
public:
    void accept(IVisitor& visitor) override {
        visitor.visit(*this);
    }
};

// 调用示例
int main() {
    ConcreteVisitable obj;
    ConcreteVisitorOne vis1;
    obj.accept(vis1);
    int res1 = vis1.get_result(); // 获取int类型返回值

    ConcreteVisitorTwo vis2;
    obj.accept(vis2);
    bool res2 = vis2.get_result(); // 获取bool类型返回值
    return 0;
}

方案2:类型擦除统一返回值(C++17及以上版本支持)

如果不想额外维护Visitor的成员变量,可以用std::any做类型擦除,统一accept的返回值类型为std::any,调用端再做对应类型转换即可:
代码示例:

#include <any>

class IVisitor {
public:
    virtual ~IVisitor() = default;
    virtual std::any visit(IVisitable& visitable) = 0;
};

class IVisitable {
public:
    virtual ~IVisitable() = default;
    virtual std::any accept(IVisitor& visitor) = 0;
};

class ConcreteVisitorOne : public IVisitor {
public:
    std::any visit(IVisitable& visitable) override {
        return 123; // 返回int
    }
};

class ConcreteVisitorTwo : public IVisitor {
public:
    std::any visit(IVisitable& visitable) override {
        return true; // 返回bool
    }
};

class ConcreteVisitable : public IVisitable {
public:
    std::any accept(IVisitor& visitor) override {
        return visitor.visit(*this);
    }
};

// 调用示例
int main() {
    ConcreteVisitable obj;
    ConcreteVisitorOne vis1;
    int res1 = std::any_cast<int>(obj.accept(vis1));

    ConcreteVisitorTwo vis2;
    bool res2 = std::any_cast<bool>(obj.accept(vis2));
    return 0;
}

如果返回类型是提前已知的有限集合,可以用std::variant代替std::any,性能更好且不会出现类型转换失败的未定义行为。


方案3:静态访问者模式(无运行时虚函数开销,适合可访问类型固定的场景)

如果你的所有ConcreteVisitable类型是编译期可枚举的,可以直接用std::variant存储所有可访问类型,配合std::visit实现静态调度,完全不需要虚函数基类,天然支持任意返回类型:

#include <variant>

// 不需要定义IVisitable、IVisitor虚基类
class ConcreteVisitableA {};
class ConcreteVisitableB {};

using VisitableVariant = std::variant<ConcreteVisitableA*, ConcreteVisitableB*>;

// 返回int的Visitor
class VisitorReturnInt {
public:
    int operator()(ConcreteVisitableA* a) { return 1; }
    int operator()(ConcreteVisitableB* b) { return 2; }
};

// 返回bool的Visitor
class VisitorReturnBool {
public:
    bool operator()(ConcreteVisitableA* a) { return true; }
    bool operator()(ConcreteVisitableB* b) { return false; }
};

// 调用示例
int main() {
    VisitableVariant obj = new ConcreteVisitableA();
    int res1 = std::visit(VisitorReturnInt{}, obj);
    bool res2 = std::visit(VisitorReturnBool{}, obj);
    return 0;
}

内容的提问来源于stack exchange,提问作者user14749247

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 22:36:00