2
class CBase { };
class CDerived: public CBase { };

CBase     b; 
CBase*    pb;
CDerived  d; 
CDerived* pd;

pb = dynamic_cast<CBase*>(&d);     // ok: derived-to-base
pd = dynamic_cast<CDerived*>(&b);  // wrong: base-to-derived

我知道“派生的基础”演员表是错误的。但它的内在原因是什么?里面的逻辑原因是什么?我猜如果没有更多解释,很难记住这一点。谢谢你!

4

4 回答 4

6

首先,CBase必须是多态的才能在dynamic_cast这里使用(也就是说,它必须至少有一个virtual成员函数)。否则,您将无法使用dynamic_cast.

也就是说,&bto的转换CDerived*没有错: pd将是一个空指针。

dynamic_cast有一个有用的属性,当转换失败时(也就是说,如果指针指向的对象不是目标类型),它会产生一个空指针。这允许您测试对象的实际类型。例如:

CBase b;
CDerived d;

CBase* pb = &b;
CBase* pd = &d;

CDerived* xb = dynamic_cast<CDerived*>(pb); // xb is null!
CDerived* xd = dynamic_cast<CDerived*>(pd); // xd points to d!

如果您使用了 ,您的代码将不正确static_cast,因为它在没有执行任何运行时类型检查的情况下进行转换,这意味着无法测试转换是否成功。如果您需要转换类层次结构并且您不确定该对象是否属于您尝试转换的派生类型,则必须使用dynamic_cast.

于 2011-03-16T04:18:59.950 回答
2

对于派生到基础的转换,您根本不需要(通常也不希望)显式指定强制转换:

CDerived d;
CBase *pb = &d;   // perfectly fine

派生演员的基础并没有真正错误,尽管您通常更愿意避免它。其背后的原因相当简单:指向 base 的指针可能指向实际的 base 对象或从它派生的任何东西。如果要像这样向下转换,一般需要检查转换是否成功。在您给出的特定情况下,它不会成功,因此分配的内容(的结果dynamic_cast)将只是一个空指针。

大多数时候,您更愿意在基类中为类的对象指定一个完整的接口,因此您很少需要向下转换。

于 2011-03-16T04:20:09.370 回答
1

派生类可以有比基类更多的“行为”。更多的成员函数,更多的成员数据等等。如果你把基类转换成派生类,然后试着把它当作派生类,你就会试图让它做它不能做的事情。因为您试图让类的实例做一些事情,所以只有派生类知道如何做。

于 2011-03-16T04:18:59.283 回答
0

pd是一个类型的指针CDerived*。因此,pd指向对象需要涉及两个子对象(即基础和派生)。但是有了这个声明——

pd = dynamic_cast<CDerived*>(&b);

这里 ,pd仅指向一个基础子对象。没有部分方式指向子对象。所以,这是错误的。

于 2011-03-16T04:21:55.010 回答