2012-08-14 94 views
2

有一个基类A,这是虚拟的dynamic_cast:应在这种情况下

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

更派生类B,C,d,E代替...

class B : public A 
{ 
}; 

class C: public A 
{ 
}; 

和类似其他入级d,E ......我们有一个指针

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)其它属性

一些aditional的属性,例如一个对象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)是否有任何优先解决方案(可能会有所不同)?

感谢您的帮助。

+0

我想,你可以在这里实现[访问者模式](http://en.wikipedia.org/wiki/Visitor_pattern) – Lol4t0 2012-08-14 20:08:54

回答

4

根据C项目90 ++编码标准(Amazon):避免型开关(无论是否带有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获得新派生类,则需要更新遍历类型的每个位置。相反,如果你依赖于虚拟函数,编译器会自动为你做。

+0

_never_非常强大,但是类型切换合适(或必要)的情况很少,远在之间。 – Chad 2012-08-14 20:00:18

+0

@Chad tnx,已更新! – TemplateRex 2012-08-14 20:02:20

+0

@ rhalbersma但我不想直接对分析的对象进行任何操作。因此,虚拟函数getID()仅适用于区分对象类型。我认为,这是一个有点不同的情况。 – justik 2012-08-14 20:05:23

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 *秒 - 你不应该现在就Fly()。如果您需要打电话,请从头开始存储Bird *。但是所有的动物都必须呼吸 - 这就是为什么这个函数是从基类继承而来的。


概括起来:如果你需要做的事情Child特异性,存储指针Child,不Base

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应该用于当您确实需要特定类型的对象时,该对象具有不能移动到基类中的抽象层的附加功能/属性。