使用 dynamic_cast 而不是传统的多态性有什么好处?
我们可以使用多态性(继承 + 虚函数)将不同的类型泛化到一个共同的基类型下,然后将不同的对象当作相同的类型来引用.
We can use Polymorphism (inheritance + virtual functions) in order to generalize different types under a common base-type, and then refer to different objects as if they were of the same type.
使用 dynamic_cast
似乎是完全相反的方法,因为本质上我们在决定我们要采取什么行动之前检查对象的特定类型.
Using dynamic_cast
appears to be the exact opposite approach, as in essence we are checking the specific type of an object before deciding what action we want to take.
有没有已知的例子说明不能像使用 dynamic_cast
那样容易地用传统的多态来实现?
Is there any known example for something that cannot be implemented with conventional polymorphism as easily as it is implemented with dynamic_cast
?
推荐答案
当你发现自己想要在基类中使用像IsConcreteX"这样的成员函数时(或者更准确地说,像ConcreteX *GetConcreteX"这样的函数),您基本上是在实现自己的 dynamic_cast
.例如:
Whenever you find yourself wanting a member function like "IsConcreteX" in a base class (edit: or, more precisely, a function like "ConcreteX *GetConcreteX"), you are basically implementing your own dynamic_cast
. For example:
class Movie
{
// ...
virtual bool IsActionMovie() const = 0;
};
class ActionMovie : public Movie
{
// ...
virtual bool IsActionMovie() const { return true; }
};
class ComedyMovie : public Movie
{
// ...
virtual bool IsActionMovie() const { return false; }
};
void f(Movie const &movie)
{
if (movie.IsActionMovie())
{
// ...
}
}
这可能看起来比 dynamic_cast
更干净,但仔细观察,您很快就会意识到,除了邪恶的"dynamic_cast
不再出现在您的代码中(前提是您没有使用未实现 dynamic_cast
的古老编译器!:)).更糟糕的是――自行编写的动态转换"方法冗长、容易出错和重复,而 dynamic_cast
无需在类定义中添加任何代码就可以正常工作.
This may look cleaner than a dynamic_cast
, but on closer inspection, you'll soon realise that you've not gained anything except for the fact that the "evil" dynamic_cast
no longer appears in your code (provided you're not using an ancient compiler which doesn't implement dynamic_cast
! :)). It's even worse - the "self-written dynamic cast" approach is verbose, error-prone and repetitve, while dynamic_cast
will work just fine with no additional code whatsoever in the class definitions.
所以真正的问题应该是在某些情况下基类知道具体派生类是否有意义.答案是:通常不会,但你肯定会遇到这种情况.
So the real question should be whether there are situations where it makes sense that a base class knows about a concrete derived class. The answer is: usually it doesn't, but you will doubtlessly encounter such situations.
用非常抽象的术语来考虑软件的一个组件,它将对象从一个部分 (A) 传输到另一部分 (B).这些对象的类型是 Class1
或 Class2
,其中 Class2
is-a Class1
.
Think, in very abstract terms, about a component of your software which transmits objects from one part (A) to another (B). Those objects are of type Class1
or Class2
, with Class2
is-a Class1
.
Class1
^
|
|
Class2
A - - - - - - - -> B
(objects)
然而,
B 仅对 Class2
有一些特殊处理.B 可能是系统的完全不同的部分,由不同的人编写,或者是遗留代码.在这种情况下,您希望在不进行任何修改的情况下重用 A 到 B 通信,并且您也可能无法修改 B.因此,明确询问您是在处理另一端的 Class1
还是 Class2
对象可能是有意义的.
B, however, has some special handling only for Class2
. B may be a completely different part of the system, written by different people, or legacy code. In this case, you want to reuse the A-to-B communication without any modification, and you may not be in a position to modify B, either. It may therefore make sense to explicitly ask whether you are dealing with Class1
or Class2
objects at the other end of the line.
void receiveDataInB(Class1 &object)
{
normalHandlingForClass1AndAnySubclass(object);
if (typeid(object) == typeid(Class2))
{
additionalSpecialHandlingForClass2(dynamic_cast<Class2 &>(object));
}
}
这是一个不使用 typeid
的替代版本:
Here is an alternative version which does not use typeid
:
void receiveDataInB(Class1 &object)
{
normalHandlingForClass1AndAnySubclass(object);
Class2 *ptr = dynamic_cast<Class2 *>(&object);
if (ptr != 0)
{
additionalSpecialHandlingForClass2(*ptr);
}
}
如果 Class2
不是叶类(即如果可能有进一步从它派生的类),这可能更可取.
This might be preferable if Class2
is not a leaf class (i.e. if there may be classes further deriving from it).
最后,这通常归结为您是从一开始就设计一个包含所有部分的整个系统,还是必须在后期修改或调整其中的一部分.但是,如果您发现自己遇到了上述问题,您可能会意识到 dynamic_cast
是在正确情况下完成正确工作的正确工具.
In the end, it often comes down to whether you are designing a whole system with all its parts from the beginning or have to modify or adapt parts of it at a later stage. But if you ever find yourself confronted with a problem like the one above, you may come to appreciate dynamic_cast
as the right tool for the right job in the right situation.
相关文章