题
我将短语这在一个示例中的形式,使之更加明确。
说我有动物的载体,我想通过数组,看看元素是狗或猫?
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的,但我真的没有任何狗对象来比较它,我想如果我能。
要避免创建狗对象有没有办法做到这一点?由于事先。
解决方案
正如其他人所指出的,你应该既不使用typeid
,也不dynamic_cast
操作来获取动态类型你的指针指向的。创建虚函数来避免这种龌龊的。
反正这里是如果您你做什么,真的想这样做(注意,访问一个迭代器会给你Animal*
因此,如果您**it
你会得到一个Animal&
):
for(std::vector<Animal*>::iterator it = v.begin(); it != v.end(); ++it) {
if(typeid(**it) == typeid(Dog)) {
// it's a dog
} else if(typeid(**it) == typeid(Cat)) {
// it's a cat
}
}
请注意可以应用typeid
操作员类型本身也如上所示。你并不需要创建一个对象这一点。还要注意的typeid方法不起作用,如果你通过它像typeid(*it)
一个指针。使用它,这样会给你只是typeid(Animal*)
这是没有用的。
类似,dynamic_cast
可以使用:
for(std::vector<Animal*>::iterator it = v.begin(); it != v.end(); ++it) {
if(Dog * dog = dynamic_cast<Dog*>(*it)) {
// it's a dog (or inherited from it). use the pointer
} else if(Cat * cat = dynamic_cast<Cat*>(*it)) {
// it's a cat (or inherited from it). use the pointer.
}
}
请注意,在这两种情况下,你的动物类型应多晶型。这意味着它必须继承或至少一个虚拟函数。
其他提示
作为载体含有动物指针可以使用dynamic_cast
,只要
vector <Animal *> stuff;
for(int i=0;i<stuff.size();i++) {
Dog *pDog = dynamic_cast <Dog *> (stuff[i]);
if(pDog) {
// do whatever with the dog
}
Cat *pCat = dynamic_cast <Cat *> (stuff[i]);
if(pCat) {
// and so on
}
}
但你应该知道,这通常不是最好的做法。你应该尽量多态的工作,不反对。换句话说,尝试写入该Animal
和Dog
覆盖虚拟Cat
功能,并让编译器自动地调用正确的一个。
(另外,dynamic_cast
是比较慢的,所以太多的将阻碍性能;而虚拟函数调用是一般只是一个单一的指令)
您确定要这么做?你要做的是多态的完全相反的东西,和多态性是面向对象程序设计的最好的事情。
宽泛地说:不要做什么的如果动物是狗的;让动物层次知道该怎么办时,它的一个对象是狗! :)
如果您真的需要你的应用程序级的识别狗与非狗,你应该避免使用RTTI(dynamic_cast
和typeid
),并作出明确的知识在你的类层次结构。
for (size_t i = 0; i != v.size(); ++i) {
if (v[i]->isDog()) { v->cleanupPoop(); }
}
有一些小的性能优势,但主要的好处是公开必要的行为,在你的类接口的维护程序员。 RTTI(即作为有限,因为它是)不应该按顺序所需的类层次结构的功能。
现在,有什么其他人一起说,这很可能是isDog()
功能可重构到的东西,并不需要整个层次的前期(如needsPoopCleanup()
)的知识。像其他人一样说,你如果你的应用程序逻辑有条件地执行基于对象无论如何键入失去多态性的好处。
您可以使用typeid
运营商要做到这一点,e.g。
if (typeid(stuff[i].getClass())==typeid(Dog))
此不能赶上如果它是一个派生类Dog
的,虽然。您可以使用dynamic_cast
了点。然而,任何使用typeid
或dynamic_cast
往往是指示设计缺陷。通常情况下,你不需要知道你的派生类型是什么,可能有涉及多态性的更好的方法。很难没有一个真实的例子给正确的意见,虽然。
使用虚拟函数:
如由其他人的应答表明,使用虚拟函数通常实际上是足够的足够,并且是思维的“C ++”方式。下面是使用虚拟函数的示例:
#include<iostream>
#include<vector>
using namespace std;
/////////////
class Animal {
public:
virtual void move() { cout << "animal just moved" << endl; }
};
class Dog : public Animal {
public:
void move() { cout << "dog just moved" << endl; }
};
class Cat : public Animal {
public:
void move() { cout << "cat just moved" << endl; }
};
void doSomethingWithAnimal(Animal *a) {
a->move();
}
/////////////
int main() {
vector<Animal*> vec;
vector<Animal*>::iterator it;
Animal *a = new Animal;
Dog *d = new Dog;
Cat *c = new Cat;
vec.push_back(a);
vec.push_back(d);
vec.push_back(c);
it = vec.begin();
while( it != vec.end() ) {
doSomethingWithAnimal(*it);
it++;
}
return 0;
}
如果这是不够的,则其他人已发布其实际使用,而不是聚合的逻辑条件逻辑的答案。
接受的答案是正确的,但你应该知道,还有另外一个选择,以及尚未被提及。你可以在称为Animal类的虚拟功能“类型()”,这可能返回int或字符串(或任何类型的比得上)。
因此,例如:
class Animal {
/*...*/
public:
virtual std::string type() const { return "animal"; }
};
class Dog: public Animal{
/*...*/
public:
virtual std::string type() const { return "dog"; }
};
class Cat: public Animal{
/*...*/
public:
virtual std::string type() const { return "cat"; }
};
这样,你可能只是这样做:
if(array[i]->type() == "dog") { }
在型函数可以返回任何东西(一个int唯一的每个派生类型将工作太,但字符串说明它更好)。
简单地另一种选择。