Dynamic_cast:在这种情况下应该被替换

时间:2012-08-14 19:53:35

标签: c++ state virtual-functions dynamic-cast

有一个基类A,它是虚拟的

class A
{
  ~virtual A() = 0;
};

和更多派生类B,C,D,E ......

class B : public A
{
};

class C: public A
{
};

类似于其他类别的D,E ......我们有一个A指针列表

std::list <A*> a_list;

我们删除任何类型未知的元素,例如

A *a = a_list.front();

根据我们决定的指向对象的类型,做什么...有更多的可能性如何做到:

A)dynamic_cast案例

将a重新转换为派生类型。

if (dynamic_cast <B*> (a))
{
   //do something (but nothing with a)
}

else if (dynamic_cast <C*> (a))
{
    //do other (but nothing with a)
}

但dynamic_cast使用表明设计不好。

B)附加属性

某些aditional属性,例如对象ID是临时的;

class A
{
  virtual ~A() = 0;
  virtual short getID() = 0;
};

class B : public A
{
  virtual short getID() {return 1;}
};

class C: public A
{
  virtual short getID() {return 2;}
};

所以修改后的条件

switch ( a->getID())
{
   case 1: // do something (but nothing with a)
   case 2: // do other (but nothing with a)
}

注意:

我们不直接对该对象执行任何操作,但根据其类型,我们会进行一些不同的计算。

问题:

1)是否应该避免使用dynamic_cast?

2)是否存在任何优先解决方案(可能与呈现的不同)?

感谢您的帮助。

3 个答案:

答案 0 :(得分:4)

根据C ++编码标准中的第90项(Amazon):避免使用类型切换(无论您是使用if-else梯形图进行操作还是dynamic_cast ,或带switch函数的getID()语句。更喜欢通过虚函数

依赖多态性
class A
{
public:
  ~virtual A() = 0;

  void fun()  // non-virtual
  { 
     // main algorithm here

     // post-processing step
     post_fun();
  }

  virtual void post_fun() = 0;
};

class B : public A
{
public:
   virtual void post_fun() { /* bla */ }
};

class C: public A
{
public:
   virtual void post_fun() { /* meow */ }
};

A* a = a_list.front();
a->fun(); // will be resolved at run-time to whatever type a points to

原因是具有显式类型切换很难维护和更新。如果从A获得新的派生类,则需要更新循环类型的每个位置。相反,如果您依赖虚函数,编译器将自动为您执行此操作。

答案 1 :(得分:0)

在大多数情况下,当您需要使用任何B特定的(保持命名)时,您应该存储B *(或shared_ptr<B>,而不是{,而不是{{1} }}。在所有其他情况下,隐藏多态性背后的一切。

考虑以下层次结构:

A *

并想象您正在存储class Animal { public: Animal() {} virtual ~Animal() = 0; virtual void Breathe(); }; class Bird : public Animal { public: Bird() {} virtual ~Bird() {} virtual void Breathe() {...} virtual void Fly() {...} }; - 您现在不应该致电Animal *。如果您需要调用它,则从头开始存储Fly()。但是所有的动物都必须呼吸 - 这就是为什么这个函数是从基类继承的。


总结一下:如果您需要执行Bird *具体操作,请将指针存储到Child,而不是Child

答案 2 :(得分:0)

通常,执行动态强制转换以获取特定类型的对象以使用它们。

struct base
{
    virtual void a() = 0;
};

struct foo : base
{
    virtual void a() { ... }
    void specificFooMethod();
};

struct bar : base
{
    virtual void a() { ... }
    void specificBarMethod();
};

base * pBase = ...;
pBase->a(); // no casting required here
if ( foo * p = dynamic_cast<foo*>(pBase) )
{
    p->specificFooMethod();
}
else if ( bar * p = dynamic_cast<bar*>(pBase) )
{
    p->specificBarMethod();
}

特定的*方法不是虚拟的,不能在没有强制转换的情况下被基接口访问。因此,当您确实需要特定类型的对象时,应使用 dynamic_cast ,这些对象具有无法移动到基类中的抽象层的其他功能/属性。