简体   繁体   English

Dynamic_cast:在这种情况下应替换

[英]Dynamic_cast: should be replaced in this case

There is a base class A, which is virtual 有一个基类A,它是虚拟的

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

and more derived classes B, C, D, E... 以及更多派生类B,C,D,E ...

class B : public A
{
};

class C: public A
{
};

and analogously for other classed D, E... We have a list of A pointers 并类似地用于其他分类的D,E ...我们有一个A指针列表

std::list <A*> a_list;

We remove any element which type is unknown, for example 例如,我们删除任何类型未知的元素

A *a = a_list.front();

Base on the type of a pointed object we decide, what to do... There more possibilities how to do that: 根据我们决定的尖锐对象的类型,该怎么做...还有更多的方法可以做到这一点:

A) dynamic_cast case A)dynamic_cast情况

Recasting of a to derived types. 重铸为派生类型。

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

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

But the dynamic_cast usage indicates a bad design. 但是dynamic_cast用法表明设计不好。

B) Additional attribute B)附加属性

Some aditional attribute, for example an object ID is impelemented; 某些附加属性(例如,对象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;}
};

So the modified condition 所以修改后的条件

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

A note: 一张纸条:

We do not perform any action directly with the object, but on the basis of its type we do some different computations. 我们不直接对对象执行任何操作,但是根据对象的类型我们进行一些不同的计算。

Questions: 问题:

1) Is it the case, when we should avoid dynamic_cast? 1)是的,应该避免dynamic_cast吗?

2) is there any prefereable solution (may be different to presented)? 2)有什么可取的解决方案(可能与提出的方案有所不同)?

Thanks for your help. 谢谢你的帮助。

According to Item 90 in C++ Coding Standards ( Amazon ): Avoid type-switching (regardless whether you do it with an if-else ladder and dynamic_cast , or a switch statement with getID() function). 根据C ++编码标准( Amazon )中的第90项:避免类型切换 (无论您是使用if-else阶梯和dynamic_cast还是使用带有getID()函数的switch语句来进行)。 Prefer instead to rely on polymorphism via virtual functions 而是通过虚拟函数依赖于多态

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

The reason is that having an explicit type-switch is hard to maintain and update. 原因是具有显式的类型开关很难维护和更新。 If you get a new derived class from A , you need to update every place where you loop over types. 如果从A获得新的派生类,则需要更新循环遍历类型的每个位置。 Instead, the compiler will do that automatically for you if you rely on virtual functions. 相反,如果您依赖虚拟函数,则编译器将自动为您执行此操作。

In most cases, when you need to use anything B -specific (keeping your naming), you should store B * (or shared_ptr<B> , rather), instead of A * . 在大多数情况下,当您需要使用特定于B任何东西(保持命名)时,应存储B * (或shared_ptr<B>而不是A * In all other cases, hide everything behind polymorphism. 在所有其他情况下,将所有内容隐藏在多态之后。

Consider following hierarchy: 考虑以下层次结构:

class Animal 
{
public:
    Animal() {}
    virtual ~Animal() = 0;
    virtual void Breathe();
};

class Bird : public Animal
{
public:
    Bird() {}
    virtual ~Bird() {}
    virtual void Breathe() {...}
    virtual void Fly() {...}
};

and imagine you're storing Animal * s - you shouldn't call Fly() now. 并想象您正在存储Animal * s-您现在不应该调用Fly() If you need to call it, then store Bird * from the beginning. 如果需要调用它,请从头开始存储Bird * But all animals must breathe - that's why the function is inherited from base class. 但是所有动物都必须呼吸-这就是为什么该功能是从基类继承的。


To sum it up: if you need to do something Child -specific, store pointer to Child , not to Base . 总结一下:如果你需要做的事情Child特异性,存储指针到Child ,而不是Base

Usually, dynamic cast are perform to get specific type of object to work with them. 通常,执行动态强制转换以获取要使用的特定对象类型。

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* methods are not virtual and can't be acccessed by base interface without casting. 特定的*方法不是虚拟的,并且在不进行强制转换的情况下不能由基本接口使用。 So dynamic_cast should be used when you really need specific type of object which have additional functionality/properties that can't be move to abstract layer in base class. 因此,当您确实需要特定类型的对象时,应使用dynamic_cast ,这些对象具有无法移至基类的抽象层的其他功能/属性。

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

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