C++ 类别识别问题
我将以示例的形式来表达这一点,以使其更加清楚。
假设我有一个动物向量,我想遍历该数组并查看元素是狗还是猫?
class Dog: public Animal{/*...*/};
class Cat: public Animal{/*...*/};
int main()
{
vector<Animal*> stuff;
//cramming the dogs and cats in...
for(/*all elements in stuff*/)
//Something to the effect of: if(stuff[i].getClass()==Dog) {/*do something*/}
}
我希望这很清楚。 我知道 typeid,但我实际上没有任何 Dog 对象可以与它进行比较,如果可以的话,我想避免创建 Dog 对象。
有没有办法做到这一点? 提前致谢。
I'll phrase this in the form of an example to make it more clear.
Say I have a vector of animals and I want to go through the array and see if the elements are either dogs or cats?
class Dog: public Animal{/*...*/};
class Cat: public Animal{/*...*/};
int main()
{
vector<Animal*> stuff;
//cramming the dogs and cats in...
for(/*all elements in stuff*/)
//Something to the effect of: if(stuff[i].getClass()==Dog) {/*do something*/}
}
I hope that's sort of clear. I know about typeid, but I don't really have any Dog object to compare it to and I would like to avoid creating a Dog object if I can.
Is there a way to do this? Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
正如其他人所指出的,您既不应该使用
typeid
也不应该使用dynamic_cast
运算符来获取指针指向的动态类型。 创建虚拟函数就是为了避免这种麻烦。无论如何,如果您真的想要这样做,那么您应该这样做(请注意,取消引用迭代器将为您提供
Animal*
。因此,如果您这样做**it< /code> 您将得到一个
Animal&
):请注意,您也可以将
typeid
运算符应用于类型本身,如上所示。 您不需要为此创建对象。 另请注意,如果您向其传递像typeid(*it)
这样的指针,则 typeid 方式不起作用。 像这样使用它只会给你typeid(Animal*)
,这是没有用的。类似地,可以使用
dynamic_cast
:请注意,在这两种情况下,您的 Animal 类型都应该是多态的。 这意味着它必须具有或继承至少一个虚函数。
As others has noted, you should neither use the
typeid
, nor thedynamic_cast
operator to get the dynamic type of what your pointer points to. virtual functions were created to avoid this kind of nastiness.Anyway here is what you do if you really want to do it (note that dereferencing an iterator will give you
Animal*
. So if you do**it
you will get anAnimal&
):Note you can apply the
typeid
operator to types itself too, as shown above. You don't need to create an object for this. Also note the typeid way doesn't work if you pass it a pointer liketypeid(*it)
. Using it like that will give you justtypeid(Animal*)
which isn't useful.Similar,
dynamic_cast
can be used:Note that in both cases, your Animal type should be polymorph. That means it must have or inherited at least one virtual function.
只要向量包含 Animal 指针,您就可以使用
dynamic_cast
。但您应该意识到这通常不是最佳实践。 您应该尝试使用多态性,而不是反对它。 换句话说,尝试编写一个由
Dog
和Cat
重写的虚拟Animal
函数,并让编译器自动调用正确的函数。(此外,
dynamic_cast
相对较慢,因此太多会影响性能;而虚拟函数调用通常只是一条指令。)You can use
dynamic_cast
, as long as the vector contains Animal pointers.but you should be aware that this is generally not the best practice. You should try to work with polymorphism, not against it. In other words, try to write a virtual
Animal
function thatDog
andCat
override, and let the compiler automagically call the right one.(Also,
dynamic_cast
is relatively slow, so too many of them will hinder performance; whereas a virtual function call is general just a single instruction.)您确定要这样做吗? 你要做的与多态性完全相反,而多态性是面向对象编程中最好的东西。
笼统地说:如果您的动物是狗,则不要做某事; 让动物层次结构知道当其对象之一是狗时该怎么做! :)
Are you sure you want to do that? What you're going to do is the exact contrary of polymorphism, and polymorphism is the best thing in object-oriented programming.
Loosely speaking: Don't do something if you animal is a Dog; let the Animal hierarchy know what to do when one of its objects is a Dog! :)
如果您确实需要应用程序级别来识别狗与非狗,则应避免使用 RTTI(
dynamic_cast
和typeid
),并在类层次结构中明确显示该知识。有一些小的性能好处,但主要的好处是向维护程序员公开类接口中的必要行为。 为了使类层次结构发挥作用,不应该需要 RTTI(尽管它是有限的)。
现在,根据其他人的说法,isDog() 函数可能会被重构为不需要预先了解整个层次结构的函数(例如 needsPoopCleanup ())。 就像其他人所说的那样,如果您的应用程序逻辑无论如何根据对象类型有条件地执行,您就会失去多态性的好处。
If you really need your application-level to identify Dogs vs non-Dogs, you should avoid using RTTI (
dynamic_cast
andtypeid
), and make that knowledge explicit in your class hierarchy.There are some minor performance benefits, but the primary benefit is exposing the necessary behavior in your class interface to maintenance programmers. RTTI (being as limited as it is) should not be required in order for a class hierarchy to function.
Now, along with what other people have said, it's likely that the
isDog()
function could be refactored into something that doesn't require knowledge of the entire hierarchy up-front (such asneedsPoopCleanup()
). Like everyone else said, you're losing the benefits of polymorphism if your application logic conditionally executes based on object type anyhow.您可以使用
typeid
运算符来执行此操作,例如,如果它是
Dog
的派生类,则无法捕获。 您可以为此使用dynamic_cast
。 但是,任何使用typeid
或dynamic_cast
通常都表明存在设计缺陷。 通常,您不需要知道派生类型是什么,并且可能有一种涉及多态性的更好方法。 不过,如果没有真实的例子,就很难给出正确的建议。You can use the
typeid
operator to do this, e.g.This can't catch if it's a derived class of
Dog
, though. You can use adynamic_cast
for that. However, any use oftypeid
ordynamic_cast
is often indicative of a design flaw. Usually, you don't need to know what your derived types are, and there's probably a better way that involves polymorphism. It's hard to give the right advice without a real example, though.使用虚函数:
正如其他人的回应所示,使用虚函数通常实际上就足够了,并且是“C++”的思维方式。 这是使用虚拟函数的示例:
如果这还不够,那么其他人已经发布了实际上使用条件逻辑而不是聚合逻辑的答案。
using virtual functions:
As indicated by others responses, using virtual functions will often actually be sufficient enough, and is the "C++" way of thinking. Here is an example of using virtual functions:
If this will not be sufficient, then others have already posted answers which actually use conditional logic instead of polymerized logic.
接受的答案是正确的,但您应该知道还有另一种选项尚未提及。 您可以在 Animal 类中有一个名为“type()”的虚函数,它可以返回 int 或字符串(或任何可比较的类型)。
例如:
这样你就可以这样做:
type 函数可以返回任何内容(每个派生类型唯一的 int 也可以工作,但字符串更好地说明了这一点)。
只是另一种选择。
The accepted answer is correct, but you should know that there is another option as well that hasn't been mentioned. You could have a virtual function in the Animal class called "type()" which could return an int or a string (or any type that is comparable).
So for example:
This way you could just do:
The type function could return anything (an int unique to each derived type would work too, but strings illustrate it better).
Simply another option.