我已经浏览了互联网,这个帖子正在寻找一个完整的 回答我面临的这种情况。我已经读到了投掷聪明 指向对象的指针不是很聪明。我只想了解原因 这是怎么回事。我会解释一下情况。让我们想象一下 简单的层次结构:
class Foo
{
public: virtual ~Foo() {}
};
typedef tr1::shared_ptr<Foo> SPFoo;
class FooInherited: public Foo { };
typedef tr1::shared_ptr<FooInherited> SPFooInherited;
让我们检查一下这个测试代码:
int main(int argc, char** argv)
{
try
{
throw FooInherited();
}
catch(const Foo& f)
{
cout << "Foo& caught!" << endl;
}
try
{
throw SPFooInherited(new FooInherited());
}
catch(const SPFoo& f)
{
cout << "SPFoo& caught!" << endl;
}
return 0;
}
一切都在编译,但在运行时第二次尝试捕获不会 执行。有人能解释一下为什么吗?特别是如果代码行像 这项工作在运行时完美无缺。
void function(const SPFoo& f)
{
}
...
SPFooInherited fi(new FooInherited());
function(fi);
我确实理解问题是SPFooInherited不从SPFoo继承(即使FooInherited继承自Foo),但它非常想知道什么是编译器/ RTE在捕获异常时与函数调用示例的不同之处不能解决de情况。是因为catch参数与函数调用参数不同吗?为什么Foo&amp;作品和SPFoo没有?
非常感谢您提前。
此致 伊克尔。
答案 0 :(得分:13)
正如您在问题中所说,SPFooInherited
不是SPFoo
的子类。这意味着catch(SPFoo const&)
将不会捕获SPFooInherited
的实例。另一方面,FooInherited
继承自Foo
,因此catch(Foo const&)
将捕获FooInherited
的实例。
要理解这一点,您不需要对编译器或运行时环境有任何特殊的了解。它只是语言的一部分。
对函数的调用有效的原因是tr1::shared_ptr
有一个模板化的非显式构造函数,允许在函数调用站点进行隐式转换。
即:tr1::shared_ptr
具有以下构造函数:
//Note the lack of explicit
template<class Y> shared_ptr(shared_ptr<Y> const & r);
这允许从不同的共享指针类型构造shared_ptr
。此构造函数的实现依赖于从FooInherited*
到Foo*
的隐式转换,以将SPFooInherited
中的指针实际存储到SPFoo
中。如果此隐式转换不存在,则代码将无法编译,因此shared_ptr
与不相关类型之间的不安全转换将不会发生。
函数调用和catch之间的根本区别在于隐式转换将在函数参数的初始化中发生,但catch只能匹配单个类型(FooInherited
is-a Foo
,所以它会匹配)。
答案 1 :(得分:3)
因为SPFoo
不是SPFooInherited
的子类。 catch
块只会捕获其捕获列表中的内容,或者捕获其捕获列表中的内容的公共子类。 FooInherited
来自Foo
,因此抓住Foo
也会让您抓住FooInherited
。 SPFoo
和SPFooInherited
是完全不同且无关的类。