C ++继承 - getClass()等价?

时间:2013-01-25 23:30:40

标签: c++ inheritance

以下面的C ++为例。

vector<Animal> listAnimal;

class Fish : Animal ...
class Mammal : Animal ...
class Bird : Animal ...

如果我然后将它们全部添加到列表中,然后将它们从列表中任意抓取,我就不知道我正在处理哪个子类。我在Java中可以getClass()thefish instanceof Fish。我如何在C ++中执行此操作?

3 个答案:

答案 0 :(得分:9)

您不应该知道您正在处理的子类的类型。如果你需要检查你正在处理的类的类型,你就不会正确地执行多态。多态性的全部意义在于减少if并使代码更加灵活。

但是在某些情况下您需要知道并且可以使用RTTI,但我建议不要这样做,特别是如果您需要很多性能(例如游戏或图形程序)。

使用typeid运算符获取有关类的信息,并确定某个类是否为特定类型。

例如:

Animal* animal1 = new Cat;

if(typeid(animal1) == typeid(Cat))
{
     cout << "animal1 is a: " << typeid(Cat).name();
}

然后使用static_cast将其抛向hiearchy。

Animal* animal1 = new Cat;

if(typeid(animal1) == typeid(Cat))
{
     Cat* cat = static_cast<Cat*>(animal1);
     cat->scratchTheLivingHellOutOfYou();
}

你可以使用dynamic_cast,它比一个更安全,但比typeid / static_cast慢得多。像这样:

Animal* animal1 = new Cat;

if(Cat* cat = dynamic_cast<Cat*>(animal1)
{
     cat->scratchTheLivingHellOutOfYou();
}

修改

dynamic_cast之所以变慢,只是因为它必须做一些额外的工作,而不仅仅是测试它是否是特定的类型和强制转换。即dyanmic_cast不等同于typeid/static_cast,但它几乎是。

想象一个超过2级深度的层次结构,例如:

class Animal { /* ... */ }; // Base
class Cat : public Animal { /* ... */ }; // 2nd level
class Tiger : public Cat { /* ... */ }; // 3rd level

假设在Cat类中,特定于所有Cats的方法称为:scratchTheLivingHellOutOfYou()。我们还要说:我有一个Animal *的列表,我想为列表中的每个Cat调用scratchTheLivingHellOutOfYou()(这包括派生自Cat类的类)。如果使用typeid运算符和static_cast,则无法实现所需。由于typeid仅检查当前类型而不关心层次结构。为此,您必须使用dynamic_cast,因为它将检查类是否从基类派生,然后相应地向上/向下抛出层次结构。

你可以在C ++中看到这个简单的例子here。以下是该计划的输出:

USING TYPEID


*scratch*
meoyawnn!
RAWR



USING DYNAMIC_CAST


*scratch*
meoyawnn!
*scratch*
RAWR

因此,您可以清楚地看到dynamic_cast比简单的typeidstatic_cast做了更多的工作。由于dynamic_cast查找了层次结构以查看是否是特定类型。简单地说...... dynamic_cast可以在层次结构中强制。而typeidstatic_cast只能将层次结构转换为特定类型。

我想提一下,如果dynamic_cast失败,它将返回一个NULL指针,或者如果你将它与引用一起使用则抛出异常。

备注:

  1. 如果你真的需要性能并且你需要检查多态对象的类型,我建议找一个RTTI的替代品。例如使用模板/宏或其他任何来识别类。
  2. 只有在您不确定对象将是您要转换为的类型时,才应使用
  3. dynamic_cast。如果你作为一名程序员,知道你所投的任何内容是100%将成为那种类型,那么使用static_cast,例如如果你知道animal1 正在成为Cat,那么static_cast更合适。

答案 1 :(得分:2)

容器只存储固定类型的元素,你想要一个指向对象的指针。

#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;   
};

答案 2 :(得分:-1)

我通常会创建一个纯虚函数,每个派生类都会实现它来告诉你它的身份。例如:

enum AnimalType
{
   Fish = 0,
   Mammal,
   Bird
}

class Animal
{
   virtual AnimalType GetType() const = 0;
}

...

AnimalType Bird::GetType()
{
   return Bird;
}

然后你可以这样做:

if (animal.GetType() == Bird)
{
   // ...
}