使用dynamic_cast时,引用和指针的行为差异

62

我正在检查dynamic_cast的行为,并发现当它失败时,只有当目标类型是引用类型时才会抛出std::bad_cast异常。如果目标类型是指针类型,则从转换中不会抛出任何异常。这是我的示例代码:

class A
{
    public:
        virtual ~A()
        {
        }
};

class B : public A
{
};

int  main()
{
    A* p = new A;

    //Using reference
    try
    {
    B& b = dynamic_cast<B&>(*p);
    }
    catch(std::bad_cast exp)
    {
    std::cout<<"Caught bad cast\n";
    }

    //Using pointer
      try
    {
    B* pB = dynamic_cast<B*>(p);

    if( pB == NULL)
    {
        std::cout<<"NULL Pointer\n";
    }
    }
    catch(std::bad_cast exp)
    {
    std::cout<<"Caught bad cast\n";
    }

    return 0;
}

输出结果为“Caught bad cast”和“NULL pointer”。代码是使用VS2008编译的。这是否是正确的行为?如果是,那么为什么会有差异?

4个回答

95

是的,这是正确的行为。原因是你可以有一个空指针,但不能有一个空引用 - 任何引用都必须绑定到一个对象。

因此,当动态转换(dynamic_cast)指针类型失败时,它返回一个空指针,调用者可以检查它,但是当它失败于引用类型时,它不能返回一个空引用,所以抛出异常是唯一合理的方法来表示问题。


39
请参阅C++标准,第5.2.7/9节:
9. 失败的指针类型转换的值是所需结果类型的空指针值。失败的引用类型转换会抛出bad_cast(18.5.2)。
至于为什么-这是Stroustrup在D&E书的第14.2.2节中的话:
当我想要检查关于引用类型的假设并认为假设错误时,我使用引用转换。如果我想从可行的替代方案中进行选择,则使用指针转换并测试结果。

5
我感谢你在这个答案中额外付出的努力,把标准和Stroustrup的解释都联系了起来。 - Stephan A. Terre

9

是的,5.2.7/9

将类型转换失败的值转换为指针类型的结果为所需结果类型的空指针值。将类型转换失败的值转换为引用类型会抛出bad_cast异常(18.5.2)。


8
是的,确实是这样。因为dynamic_cast无法返回失败引用转换的NULL值,所以异常是唯一的出路。
也就是说,引用不能为NULL,因此没有合适的返回值。

1
但是为什么指针也不能抛出异常呢? - Naveen
3
那么你需要尝试捕获每个dynamic_cast,这是不好的代码。相反,你可以取地址,进行dynamic_cast并检查是否为空。 - sharptooth
1
另外,抛出和捕捉异常相对来说是代价昂贵的,我认为设计师们想找到一种方式来尽量减少这样的成本。 - Kim Gräsman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接