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

如何在C++中实现类似Java的带泛型返回值的访问者模式抽象方法

方案1:保留原类继承结构,将返回值下沉到Visitor实现

C++不允许模板虚函数的核心原因是虚函数表需要在编译期确定所有虚函数签名,而模板方法会在调用时生成不同签名的实例,无法提前纳入虚表。
如果你不想使用std::any类的类型擦除容器,最简单的改造是把返回值存储在Visitor实例内部,将accept方法改为void返回,不需要通过返回值传递结果:

#include <iostream>

class VisitableA;
class VisitableB;

// 非模板Visitor基类
class Visitor {
public:
    virtual void visitA(VisitableA& a) = 0;
    virtual void visitB(VisitableB& b) = 0;
    virtual ~Visitor() = default;
};

// 自定义返回int的Visitor
class MyVisitor : public Visitor {
    int result{};
public:
    void visitA(VisitableA& a) override { 
        /* 自定义逻辑 */
        result = 42; 
    }
    void visitB(VisitableB& b) override { 
        /* 自定义逻辑 */
        result = 1337; 
    }
    int getResult() const { return result; }
};

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

class VisitableA : public Visitable { 
public:
    void accept(Visitor& visitor) override { 
        visitor.visitA(*this); 
    }
};

class VisitableB : public Visitable { 
public:
    void accept(Visitor& visitor) override { 
        visitor.visitB(*this); 
    }
};

// 使用示例
int main() {
    Visitable* a = new VisitableA();
    MyVisitor visitor;
    a->accept(visitor);
    std::cout << visitor.getResult() << std::endl; // 输出42
    delete a;
    return 0;
}

如果需要支持不同返回类型,只需要实现不同的Visitor子类,每个子类对应一种返回类型,获取结果时调用对应子类的get方法即可,全程不需要类型擦除。


方案2:使用std::variant实现无继承的访问者模式(C++17及以上推荐)

C标准库提供的std::variant类型天然适配访问者模式,完全不需要定义虚函数、accept方法,也不会遇到模板虚函数的限制,是C中实现访问者模式的首选方案:

#include <iostream>
#include <variant>
#include <vector>

// 不需要继承任何基类
class VisitableA {};
class VisitableB {};

using Visitable = std::variant<VisitableA, VisitableB>;

int main() {
    std::vector<Visitable> items = {VisitableA{}, VisitableB{}};
    for (auto& item : items) {
        // C++20 泛型lambda写法,返回值自动推导
        auto res = std::visit(
            []<typename T>(T& elem) -> int {
                if constexpr (std::is_same_v<T, VisitableA>) {
                    return 42;
                } else if constexpr (std::is_same_v<T, VisitableB>) {
                    return 1337;
                }
            },
            item
        );
        std::cout << res << std::endl; // 依次输出42、1337
    }
    return 0;
}

这种实现的性能比继承实现的访问者模式更高,返回值类型可以在调用std::visit时由传入的访问逻辑动态决定,不需要在Visitable构造时确定返回类型,完全符合需求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 19:57:03