如何检查对象的类型是否是 C 中的特定子类?
我正在考虑使用 typeid()
但我不知道如何询问该类型是否是另一个类的子类(顺便说一句,它是抽象的)
I was thinking along the lines of using typeid()
but I don't know how to ask if that type is a subclass of another class (which, by the way, is abstract)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(15)
你真的不应该。 如果您的程序需要知道对象是什么类,这通常表明存在设计缺陷。 看看是否可以使用虚函数获得您想要的行为。 此外,有关您正在尝试做什么的更多信息也会有所帮助。
我假设你遇到这样的情况:
如果这就是你所遇到的情况,那么尝试做这样的事情:
编辑:由于关于这个答案的争论在这么多年后仍然在继续,我想我应该添加一些参考资料。 如果您有一个指向基类的指针或引用,并且您的代码需要知道该对象的派生类,那么它违反了 里氏替换原则。 鲍勃叔叔 将此称为“面向对象设计的诅咒"。
You really shouldn't. If your program needs to know what class an object is, that usually indicates a design flaw. See if you can get the behavior you want using virtual functions. Also, more information about what you are trying to do would help.
I am assuming you have a situation like this:
If this is what you have, then try to do something like this:
Edit: Since the debate about this answer still goes on after so many years, I thought I should throw in some references. If you have a pointer or reference to a base class, and your code needs to know the derived class of the object, then it violates Liskov substitution principle. Uncle Bob calls this an "anathema to Object Oriented Design".
您可以使用
dynamic_cast
(至少对于多态类型)来做到这一点。实际上,再想一想,您无法通过
dynamic_cast
判断它是否是特定类型 - 但您可以判断它是否是该类型或其任何子类。You can do it with
dynamic_cast
(at least for polymorphic types).Actually, on second thought--you can't tell if it is SPECIFICALLY a particular type with
dynamic_cast
--but you can tell if it is that type or any subclass thereof.下面的代码演示了 3 种不同的实现方法:
的程序打印出以下内容:
The code below demonstrates 3 different ways of doing it:
The program above prints this:
dynamic_cast
可以确定类型是否在继承层次结构中的任何位置包含目标类型(是的,这是一个鲜为人知的功能,如果B
继承自A
和C
,它可以将A*
直接变成C*
)。typeid()
可以确定对象的确切类型。 然而,这些都应该非常谨慎地使用。 正如已经提到的,您应该始终避免动态类型识别,因为它表明了设计缺陷。 (此外,如果您确定该对象是目标类型,则可以使用static_cast
进行向下转型。Boost 提供了polymorphic_downcast
,它将使用 < code>dynamic_cast 和assert
在调试模式下,在发布模式下它只会使用static_cast
)。dynamic_cast
can determine if the type contains the target type anywhere in the inheritance hierarchy (yes, it's a little-known feature that ifB
inherits fromA
andC
, it can turn anA*
directly into aC*
).typeid()
can determine the exact type of the object. However, these should both be used extremely sparingly. As has been mentioned already, you should always be avoiding dynamic type identification, because it indicates a design flaw. (also, if you know the object is for sure of the target type, you can do a downcast with astatic_cast
. Boost offers apolymorphic_downcast
that will do a downcast withdynamic_cast
andassert
in debug mode, and in release mode it will just use astatic_cast
).我不知道我是否正确理解你的问题,所以让我用自己的话重述一下......
问题:给定类
B
和D
,确定是否D
是B
的子类(反之亦然?)解决方案:使用一些模板魔法! 好吧,说实话,您需要看看 LOKI,这是一个由著名的 C++ 作者 Andrei Alexandrescu 制作的出色的模板元编程库。
更具体地说,下载 LOKI 并包含标头
TypeManip .h
,然后在源代码中使用SuperSubclass
类模板,如下所示:根据文档,
SuperSubClass::value
将是如果B
是D
的公共基类,或者如果B
和D
是同一类型的别名,则为 true。即
D
是B
的子类,或者D
与B
相同。我希望这有帮助。
编辑:
请注意,与某些使用
dynamic_cast
的方法不同,SuperSubClass::value
的评估发生在编译时,因此有在运行时使用该系统不会受到任何惩罚。I don't know if I understand your problem correctly, so let me restate it in my own words...
Problem: Given classes
B
andD
, determine ifD
is a subclass ofB
(or vice-versa?)Solution: Use some template magic! Okay, seriously you need to take a look at LOKI, an excellent template meta-programming library produced by the fabled C++ author Andrei Alexandrescu.
More specifically, download LOKI and include header
TypeManip.h
from it in your source code then use theSuperSubclass
class template as follows:According to documentation,
SuperSubClass<B,D>::value
will be true ifB
is a public base ofD
, or ifB
andD
are aliases of the same type.i.e. either
D
is a subclass ofB
orD
is the same asB
.I hope this helps.
edit:
Please note the evaluation of
SuperSubClass<B,D>::value
happens at compile time unlike some methods which usedynamic_cast
, hence there is no penalty for using this system at runtime.我不同意你永远不应该在 C++ 中检查对象的类型。 如果你能避免它,我同意你应该这样做。 不过,说在任何情况下都不应该这样做就太过分了。 您可以使用多种语言来完成此操作,这可以让您的生活变得更加轻松。 例如,Howard Pinsley 在他关于 C# 的文章中向我们展示了如何操作。
我使用 Qt 框架做了很多工作。 一般来说,我会模仿他们做事的方式(至少在他们的框架中工作时)。 QObject 类是所有 Qt 对象的基类。 该类具有 isWidgetType() 和 isWindowType() 函数作为快速子类检查。 那么为什么不能检查您自己的派生类,它在本质上是可比较的呢? 这是从其他一些帖子中衍生出来的 QObject:
然后,当您传递指向 QObject 的指针时,您可以通过调用静态成员函数来检查它是否指向您的派生类:
I disagree that you should never want to check an object's type in C++. If you can avoid it, I agree that you should. Saying you should NEVER do this under any circumstance is going too far though. You can do this in a great many languages, and it can make your life a lot easier. Howard Pinsley, for instance, showed us how in his post on C#.
I do a lot of work with the Qt Framework. In general, I model what I do after the way they do things (at least when working in their framework). The QObject class is the base class of all Qt objects. That class has the functions isWidgetType() and isWindowType() as a quick subclass check. So why not be able to check your own derived classes, which is comparable in it's nature? Here is a QObject spin off of some of these other posts:
And then when you are passing around a pointer to a QObject, you can check if it points to your derived class by calling the static member function:
结果:
Result:
嗯,是的,可以通过比较来完成:
typeid().name()
。 如果我们采用已经描述的情况,其中:foo(Base *p) 的可能实现将是:
Well, yes, it could be done by comparing:
typeid().name()
. If we take the already described situation, where:A possible implementation of
foo(Base *p)
would be:我在这里看到了一些好的答案,也看到了一些愚蠢的答案。
“尝试查询对象的类型是一个设计缺陷”。 这意味着 Java instanceof 和 C# is 关键字是设计缺陷。 这些是不评价多态性的人的反应。 如果您有一个接口,则该接口是由另一个实现更多功能的接口派生的。 如果您需要这些额外的功能,您必须首先检查您是否有这样的接口。 甚至微软的 COM API 也使用了这种设计。
那么就如何推断一个对象是否是类的实例而言,已经给出了许多好的答案
is_base_of 与多态性无关。
让每个虚函数定义自己的类型方法是不必要的,因为它是多余的。 每个虚拟类已经有一个指向其虚拟表的指针。
这里的要点是,虚拟表的地址是固定的,简单的比较将决定虚拟对象是否是虚拟类的实例。
由于 cpp 没有为我们提供访问虚拟表的标准方法,因此很难手动进行这些比较。 但是 cpp 抽象机在推导虚拟对象的确切实例时绝对没有问题。
I see some good answers here and I see some dumb response.
"Trying to query the type of an object is a design flaw". Which means that Java instanceof and C# is keywords are design flaws. These are response of people that dont rate polymorphism. If you have an interface, that interface is derived by another interface that impelments more features. If you need these extra features you must first check that you have such an interface. Even microsoft COM API makes use of this design.
Then in terms of how to deduce if an object is a instanceof a class, many good answers have already been given
is_base_of has nothing to do with polymorphism.
And having each virtual function define its own type method is unnecessary as it is redundant. Each virtual class already has a pointer to its virtual table.
The point here is that the address of the virtual tables are fixed and a simple comparrison will decide if a virtual object is an instanceof a virtual class.
Since cpp doesnt give us a standard way of accessing the virtual tables, it would be hard to do these comparrisons manually. But the cpp abstract machine has absolutely no problems deducing the exact instance of a virtual object.
除非使用 RTTI,否则只能在编译时使用模板执行此操作。
它允许您使用 typeid 函数,该函数将生成一个指向 type_info 结构的指针,该结构包含有关类型的信息。
阅读维基百科
You can only do it at compile time using templates, unless you use RTTI.
It lets you use the typeid function which will yield a pointer to a type_info structure which contains information about the type.
Read up on it at Wikipedia
您可以使用模板(或SFINAE(替换失败不是错误))来完成此操作。 示例:
输出:
You can do it with templates (or SFINAE (Substitution Failure Is Not An Error)). Example:
Output:
作为多个其他答案(包括我之前自己发布的答案!)的衍生,这里有一个可以提供帮助的宏:
As a spin off of multiple other answers (including one I previously posted myself!), here's a macro to help:
我为指针和引用参数定义了 2 个宏。 如果您与一个版本一致,则可以注释掉另一个版本并将其重命名为INSTANCEOF。
======
I define 2 macros for pointer and reference params. If you're consistent with one version, you can comment out the other and re-name it as INSTANCEOF only.
======
在 C# 中你可以简单地说:
In c# you can simply say: