我有一个像这样的节点树结构:
struct Node {};
struct ChildNode : Node{};
我将这样做:
Node* n = new ChildNode;
稍后,我需要知道节点类型:
if (IsChildNode(n)) {
ChildNode* c = static_cast<ChildNode*>(n);
// ...
}
通常,我通过向Node基类添加虚拟Id()
方法并在派生类中重写此方法来实现此目的。
在我当前的情况下,这是唯一需要虚拟的方法,因此我试图查看是否有一种避免虚拟方法的方法,同时使Id成为编译时值(不是Node类中的非常量成员变量)。
有没有一种方法可以找出ChildNode的类型:
我在Visual Studio 2019上使用C ++ 17,
答案 0 :(得分:1)
广义上,您有一个指针和一个指向的对象:
Node* ChildNode
+------+ +------------------
| XXXX | -----> | ... some data ...
+------+ +------------------
如果您需要在运行时确定指向对象的类型,而无需选择静态类型系统(包括模板),则这两个地方是 only 的来源信息。
通过拒绝使用dynamic_cast
和virtual
函数,您已经消除了C ++内置的用于动态类型信息的机制。通过拒绝使用成员变量,您还消除了以类似方式手动实现类型检查的可能性。除非不同的Node
类型在对象中存储了其他唯一值,否则无法使用指向的对象的值来确定其类型。
但是,指针本身可以成为信息的来源。例如,在标准用法下,指针可以通过与null比较来指示它确实指向了一个对象。我在评论中开玩笑地指出,可以为每种Node
类型使用唯一的分配器,这些分配器可以标识它们自己的指针。但在有限制的情况下,它是一个 选项。这必须通过以下方式实现:
这些选项中的任何一个都没有任何好处。 RTTI和成员变量都是解决问题的非常常用的方法。我不鼓励您使用上面列出的机制中的 any 。
我无法使用规范回答,因为不可能证明是否定的。但是,我希望我已经从概念上证明了这种选择很少。
答案 1 :(得分:0)
我正在查看LLVM如何进行投射。几乎可以肯定,它们的实现将是最快的。以下是与此有关的一些文件:
https://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html
http://llvm.org/docs/ProgrammersManual.html#the-isa-cast-and-dyn-cast-templates
https://llvm.org/doxygen/Casting_8h_source.html
基本上,他们具有这样的设置:
enum class Kind {
ChildNode
};
struct Node {
Node(Kind k) : kind(k) {}
const Kind kind;
};
struct ChildNode : Node {
ChildNode() : Node(Kind::ChildNode) {}
static bool classof(const Node* n) { return n->kind == Kind::ChildNode;}
};
然后,他们做了一些模板欺骗来定义泛型函数:
bool isa<TypeToCheckFor, CurrentType>(const CurrentType& t);
可以叫哪个来检查类型。
尽管此版本不符合我的这一要点:
* Without setting a runtime variable in the Node class.
至少,它使用const基本类型成员,没有虚拟调用和const参数。这将是设置的最佳选择,因为编译器可能必须对这些检查执行尽可能多的优化。