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の場合

派生型への再キャスト。

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)好ましい解決策はありますか(提示されたものとは異なる場合があります)?

ご協力いただきありがとうございます。

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

ほとんどの場合、特定のものを使用する必要がある場合(名前を付けたままにする場合)、。の代わりに(または、ではなく)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() {...}
};

そして、あなたがsを保存していると想像してくださいAnimal *-あなたは今電話するべきではありませんFly()。電話をかける必要がある場合はBird *、最初から保存してください。しかし、すべての動物は呼吸しなければなりません-それが機能が基本クラスから継承されている理由です。


要約すると、特定のことを行う必要がある場合は、へのポインタではなく、へのChildポインタを格納します。ChildBase

于 2012-08-14T20:15:31.090 に答える
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を使用する必要があります。

于 2012-08-14T20:20:21.487 に答える