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
我知道“衍生的基础”演员是错误的。但它的内在原因是什么?内在的逻辑原因是什么?我想,如果没有更多的解释,很难记住这一点。 谢谢!
答案 0 :(得分:6)
首先,CBase
必须是多态的,才能在这里使用dynamic_cast
(也就是说,它必须至少有一个virtual
成员函数)。否则,您无法使用dynamic_cast
。
也就是说,&b
到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
。
答案 1 :(得分:2)
对于派生到基本转换,您根本不需要(通常不会想要)明确指定强制转换:
CDerived d;
CBase *pb = &d; // perfectly fine
派生演员的基础并不是真的错,尽管你通常更愿意避免它。这背后的原因很简单:指向base的指针可能指向一个实际的基础对象或从它派生的任何东西。如果你要像这样下传,你通常需要检查转换是否成功。在您给出的特定情况下,它将不会成功,因此分配的内容(dynamic_cast
的结果)将只是一个空指针。
大多数情况下,您更喜欢在基类中指定类的对象的完整接口,因此您很少需要向下转换。
答案 2 :(得分:1)
派生类可以比基类具有更多“行为”。更多成员函数,更多成员数据等。如果将基类强制转换为派生类,然后尝试将其视为派生类,则会尝试使其执行不能执行的操作。因为您尝试创建 base 类的实例,所以只有派生的类知道该怎么做。
答案 3 :(得分:0)
pd
是CDerived*
类型的指针。因此,pd
指向对象需要涉及两个子对象(即,base&amp; derived)。但是有了这个陈述 -
pd = dynamic_cast<CDerived*>(&b);
这里,pd
仅指向基础子对象。没有指向子对象的部分方式。所以,这是错误的。