2

有一个基类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) 附加属性

一些额外的属性,例如对象 ID 是 impelemented;

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)是否有任何优选的解决方案(可能与提出的不同)?

谢谢你的帮助。

4

3 回答 3

4

根据 C++ 编码标准 ( Amazon ) 中的第 90 条:避免类型切换(无论您是使用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,则需要更新循环类型的每个位置。相反,如果您依赖虚函数,编译器会自动为您执行此操作。

于 2012-08-14T19:57:47.167 回答
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();
}

specific* 方法不是虚拟的,并且不能通过基本接口访问而不进行强制转换。因此,当您确实需要具有无法移动到基类中的抽象层的附加功能/属性的特定类型的对象时,应该使用dynamic_cast 。

于 2012-08-14T20:20:21.487 回答
0

在大多数情况下,当你需要使用任何特定的东西B(保持你的命名)时,你应该存储B *(或者shared_ptr<B>,更确切地说),而不是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 *s - 你现在不应该打电话Fly()。如果您需要调用它,则Bird *从头开始存储。但是所有的动物都必须呼吸——这就是为什么函数是从基类继承的。


总结一下:如果您需要做一些特定的事情Child,请将指针存储到Child,而不是Base

于 2012-08-14T20:15:31.090 回答