繁体   English   中英

Dynamic_cast:在这种情况下应替换

[英]Dynamic_cast: should be replaced in this case

有一个基类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情况

重铸为派生类型。

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)已失效;

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)有什么可取的解决方案(可能与提出的方案有所不同)?

谢谢你的帮助。

根据C ++编码标准( Amazon )中的第90项:避免类型切换 (无论您是使用if-else阶梯和dynamic_cast还是使用带有getID()函数的switch语句来进行)。 而是通过虚拟函数依赖于多态

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获得新的派生类,则需要更新循环遍历类型的每个位置。 相反,如果您依赖虚拟函数,则编译器将自动为您执行此操作。

在大多数情况下,当您需要使用特定于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

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

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 ,这些对象具有无法移至基类的抽象层的其他功能/属性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM