c++ - 抽象方法的 C++ 模板返回类型(类似于 java)
问题描述
假设我有一个 Java 访问者。
interface Visitor<T> {
T visitA(VisitableA a);
T visitB(VisitableB b);
}
abstract class Visitable {
abstract <T> T accept(Visitor<T> visitor);
}
class VisitableA extends Visitable {
@Override <T> T accept(Visitor<T> visitor) {
return visitor.visitA(this);
}
}
class VisitableB extends Visitable {
@Override <T> T accept(Visitor<T> visitor) {
return visitor.visitB(this);
}
}
现在,如果我想用 C++ 编写它,我可以这样做
class VisitableA;
class VisitableB;
template <typename T> class Visitor {
virtual T visitA(VisitableA& a) = 0;
virtual T visitB(VisitableB& b) = 0;
};
class MyVisitor : public Visitor<int> {
int visitA(VisitableA& a) override { /* do something */ return 42; }
int visitB(VisitableB& b) override { /* do something */ return 1337; }
};
class Visitable {
template <typename T> virtual T accept(Visitor<T>& visitor) = 0;
};
class VisitableA : public Visitable {
template <typename T> T accept(Visitor<T>& visitor) override { return visitor.visitA(*this); }
};
class VisitableB : public Visitable {
template <typename T> T accept(Visitor<T>& visitor) override { return visitor.visitB(*this); }
};
但这不会编译,因为我不能有一个虚拟模板方法。
我可以使用std::any
(或类似的东西),但我想知道是否有办法在没有它的情况下实现它。
必须注意的accept
是,在构造 s 时返回类型是未知Visitable
的。
如果需要,C++20 也可以。
解决方案
做 Java 在底层所做的事情。
替换T
为std::any
。
用于Visitable
创建返回any
两种方法的基类。any
然后创建一个实现返回 as的模板类final
,并创建一个T
返回Visit
as pure 供实现者实现。
Visitable
有两种方法;一个采用 的纯虚拟私有模板,一个采用模板Visitable
的公共VitiableT
模板。它调用纯虚拟的并将 转换any
为 a T
。
Java 泛型基本上只是为您编写粘合剂。
您可能需要在引擎盖下进行强制转换,或者查看 typeids,这取决于您如何使用它。
struct VistableA; struct VistableB;
struct Visitor{
virtual std::any visitA(VisitableA&)=0;
virtual std::any visitB(VisitableB&)=0;
};
template<class T>
struct VisitorT:Visitor{
std::any visitA(VisitableA& a) final{ return visitTA(a); }
T visitTA(VisitableA& a) = 0;
std::any visitB(VisitableB& b) final{ return visitTB(b); }
T visitTB(VisitableB& b) = 0;
};
class MyVisitor : public VisitorT<int> {
int visitTA(VisitableA& a) override { /* do something */ return 42; }
int visitTB(VisitableB& b) override { /* do something */ return 1337; }
};
class Visitable {
template <typename T> T accept(VisitorT<T>& visitor) {
return std::any_cast<T>(accept(static_cast<Visitor&>(visitor)));
}
virtual std::any accept(Visitor& visitor)=0;
};
class VisitableA : public Visitable {
std::any accept(Visitor& visitor) override { return visitor.visitA(*this); }
};
class VisitableB : public Visitable {
std::any accept(Visitor& visitor) override { return visitor.visitB(*this); }
};
现在这是 C++,还有另外六种方法可以解决您的问题,它们不模拟 Java。但这是 Java 式的方式。
请注意,因为我们正在编写 Java 为您编写的胶水代码,如果我们在胶水中出错,我们就不是类型安全的。
并且在VisitableA
Java 中检查所有T
s 是否使用相同的“通用类型”;在 C++ 中,我使用了 a std::any
,它可能与其他“泛型”混合并破坏了某些类型安全。你可以想象一个复杂的标记系统std::any
来避免这种情况。
推荐阅读
- python - 如果日期在时间范围内,则合并数据框
- numpy - 用 numpy 计算二进制掩码 IOU 的最快方法
- itfoxtec-identity-saml2 - 我如何在 azure ad asp.net core (itfoxtec) 中设置多个租户的流程
- google-sheets - 谷歌表格查询聚合函数分组可变日期
- dynamics-business-central - Business Central:如何使用 OData URL 在页面中显示公司或任何其他实体数据?
- docker - 如何使用 powershell 安装 docker
- postgresql - 使用 db 作为 elasticsearch 缓存
- tensorflow - 配置LSTM参数?
- osgi - Instanceof 与 OSGI 捆绑包(Eclipse RCP)的不合理结果比较
- rollupjs - 如何定义全局变量以从模块导入多个导出?