以下面的 C++ 为例。
vector<Animal> listAnimal;
class Fish : Animal ...
class Mammal : Animal ...
class Bird : Animal ...
如果我然后将它们全部添加到列表中,然后任意将它们从列表中取出,我将不知道我正在处理哪个子类。我在 Java 中可以做getClass()
或thefish instanceof Fish
. 我如何在 C++ 中做到这一点?
以下面的 C++ 为例。
vector<Animal> listAnimal;
class Fish : Animal ...
class Mammal : Animal ...
class Bird : Animal ...
如果我然后将它们全部添加到列表中,然后任意将它们从列表中取出,我将不知道我正在处理哪个子类。我在 Java 中可以做getClass()
或thefish instanceof Fish
. 我如何在 C++ 中做到这一点?
你不需要知道你正在处理什么类型的子类。如果您需要检查您正在处理的类的类型,那么您就没有正确地进行多态性。多态性的全部意义在于减少 if 并使您的代码更加灵活。
在某些情况下您需要知道,您可以使用RTTI。但是我建议不要这样做,特别是如果您需要大量性能(例如游戏或图形程序)。
使用typeid
运算符获取有关类的信息,并确定类是否为特定类型。
例如:
Animal* animal1 = new Cat;
if(typeid(animal1) == typeid(Cat))
{
cout << "animal1 is a: " << typeid(Cat).name();
}
然后使用 astatic_cast
将其向下转换层次结构。
Animal* animal1 = new Cat;
if(typeid(animal1) == typeid(Cat))
{
Cat* cat = static_cast<Cat*>(animal1);
cat->scratchTheLivingHellOutOfYou();
}
或者,您可以使用dynamic_cast
比 typeid/static_cast 更安全但慢得多的 a。像这样:
Animal* animal1 = new Cat;
if(Cat* cat = dynamic_cast<Cat*>(animal1)
{
cat->scratchTheLivingHellOutOfYou();
}
dynamic_cast
速度较慢仅仅是因为它必须做一些额外的工作,而不仅仅是测试它是否是特定类型和强制转换。iedyanmic_cast
不等于typeid/static_cast
,但几乎是。
想象一个深度超过 2 层的层次结构,例如:
class Animal { /* ... */ }; // Base
class Cat : public Animal { /* ... */ }; // 2nd level
class Tiger : public Cat { /* ... */ }; // 3rd level
假设在 Cat 类中,调用了特定于所有 Cat 的方法:scratchTheLivingHellOutOfYou()
。还可以这样说:我有一个 Animals 列表,我想调用scratchTheLivingHellOutOfYou()
列表中的每个 Cat(这包括派生自 Cat 类的类)。如果使用typeid
and 运算符static_cast
,这将无法实现所需的功能,因为typeid
只检查当前类型而不关心层次结构。为此,您必须使用 a dynamic_cast
,因为它会检查一个类是否派生自基类,然后相应地向上/向下转换层次结构。
您可以在此处查看这个简单的 C++ 示例。这是程序的输出:
USING TYPEID
*scratch*
meoyawnn!
RAWR
USING DYNAMIC_CAST
*scratch*
meoyawnn!
*scratch*
RAWR
因此,您可以清楚地看到,它比简单的anddynamic_cast
做了更多的工作。由于查找层次结构以查看它是否是特定类型。简单地说......可以上下层级。而 a and只能将层次结构向下转换为特定类型。typeid
static_cast
dynamic_cast
dynamic_cast
typeid
static_cast
我想我会提到,如果dynamic_cast
失败,它将返回一个 NULL 指针,或者如果您将它与引用一起使用,则抛出异常。
dynamic_cast
仅当您不确定对象是否是您要转换的类型时才应使用。如果你,作为一个程序员,知道你正在铸造的任何东西都是 100% 将是那种类型,那么使用static_cast
,例如,如果你知道 animal1将是 aCat
那么static_cast
更合适。容器仅存储固定类型的元素,您需要指向对象的指针。
#include <memory>
#include <vector>
std::vector<std::unique_ptr<Animal>> animal_list;
animal_list.emplace_back(new Fish);
animal_list.emplace_back(new Mammal);
animal_list.emplace_back(new Bird );
将派生类型推入 listAnimal 时Animal
,会导致在向量中存储类型。object slice
vector<Animal> listAnimal;
listAnimal.push_back(Fish); // Fish is sliced to Animal, no fish for you.
编辑:
要知道衍生动物是什么类型,您可以将其存储在成员中
Enum AnimalType
{
FISH,
MAMAL,
BIRD
};
class Animal
{
public:
Animal(AnimalType animal_type) : type(animal_type) {}
AnimalType GetType() const { return type; }
private:
AnimalType type;
};
我通常创建一个纯虚函数,每个派生类都实现它来告诉你它的身份。例子:
enum AnimalType
{
Fish = 0,
Mammal,
Bird
}
class Animal
{
virtual AnimalType GetType() const = 0;
}
...
AnimalType Bird::GetType()
{
return Bird;
}
然后你可以做这样的事情:
if (animal.GetType() == Bird)
{
// ...
}