2012-02-23 72 views
2

我注意到了std :: bad_cast异常,引用和指针似乎没有相同的方式。例如:std :: bad_cast指针与参考情况

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

//Case #1 
int main() 
{ 
    A a; 
    B& b = dynamic_cast<B&>(a); //Would throw std::bad_cast. 
} 

//Case #2 
int main() 
{ 
    A* a = new A; 
    B* b = dynamic_cast<B*>(a); //Would not throw std::bad_cast. 
} 

在第一种情况中,产生的std :: bad_cast的一个异常,并且在第二情况下产生也不例外 - 相反,在B刚指针被分配值NULL。

有人可以向我解释为什么只有前者抛出一个异常,当这两个都是bad_cast的例子?我认为这个决定背后有一个很好的动机,并且我滥用了一些东西,因为我不明白这个动机。

+0

你会怎么做呢?当你只是在没有偏见的情况下检查时使用指针,而且这种情况通常是失败的。另一方面,当你知道演员应该成功时使用引用,并在适当的检查点捕获异常。 – 2012-02-23 19:32:01

回答

6

有人可以向我解释为什么只有前者抛出异常?

那是怎样dynamic_cast指定的行为:一个坏的dynamic_cast涉及指针产生一个空指针,但没有空引用,所以不好dynamic_cast涉及引用抛出一个bad_cast

发生故障的dynamic_cast涉及指针产生一个空指针是非常有用的,因为它允许对更清洁,更简单的类型检查,并允许下列成语的事实:

if (B* b = dynamic_cast<B*>(a)) 
{ 
    // The dynamic_cast succeeded and 'b' is non-null. 
} 

有了这个成语,b是在范围和当且仅当它非空时才可用。

+0

尽管通常我们会考虑做不好的编程技术,因为我们基于'运行时类型'进行分支而不是使用虚拟函数。 – 2012-02-23 20:06:23

+0

@LokiAstari:我认为这取决于情况。当然,虚拟功能在可用时应该是首选。 – 2012-02-23 22:50:21

2

引用必须绑定到包含有效内存地址的对象......它们不能被“未初始化”,也不会有默认的非绑定初始化值。请注意,C++ 11标准状态中的第8.5节/ 8节,

调用引用类型实体的缺省初始化或值初始化的程序是格式不正确的。

另一方面,指针变量只是包含指向其他存储器地址的值的存储器地址,因此可以具有NULL值。

所以如果按照标准dynamic_cast<T&>操作必须返回一个有效的内存地址绑定到引用变量,那么如果动态转换失败,它不能返回一个“非值”...唯一的选择是抛出异常。