簡體   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