我能做到这一点,没有任何问题:为什么的try ... catch需要确切类型抛出
long lngval = 3L;
int i = lngval;
但如果我试试这个:
try {
throw 3L;
}
catch(int i) {
cout << "caught " << i << endl;
}
我得到一个未处理的异常。
这似乎不一致。在这种情况下没有类型转换的原因是什么?
我能做到这一点,没有任何问题:为什么的try ... catch需要确切类型抛出
long lngval = 3L;
int i = lngval;
但如果我试试这个:
try {
throw 3L;
}
catch(int i) {
cout << "caught " << i << endl;
}
我得到一个未处理的异常。
这似乎不一致。在这种情况下没有类型转换的原因是什么?
在第一种情况下,编译器可以准确地知道你想要做什么:将long
转换为int
。在第二种情况下,编译器必须假设,你可能有这样的结构:
try {
try {
throw 3L;
}
catch (int i) { /* P */ }
}
catch (long l) { /* Q */ }
的想法是,编译器无法知道是否有可能是一个catch (long l)
潜伏在当前的上下文之外,所以它永远不会安全地选择第一个可能的转换。
这也是为什么它的共同抛出异常时,而不是随机的类型,如int
或long
使用类层次结构:它可以很容易地以这样的方式,编译器可以或多或少规范添加到您的异常处理程序确定你的意图(通过is-a关系)。
您可以在一个try-catch块中捕获多个类型。为了让编译器知道要抛出哪个catch块,它必须能够匹配确切的类型。或者它可以有一个默认的catch块 - catch (...) {}
,但是你将无法得到这种情况下抛出的值。
catch语句在给定类型的情况下捕获一个对象(或者标量变量),所以如果类型不匹配,它将传递给下一个catch语句(如果有的话)或默认的异常接收者。
就你而言,你可以有第二个catch语句捕获很长时间,也许在别的地方,所以你的catch语句不会捕获任何东西。
捕捉任何异常,只是使用捕捉(){} :)
单尖,更好的使用异常类,或者继承它适合你自己的需要:)
你也可以throw 3;
- 没问题。
int
和long
是不同的类型。除了查看它们的类型之外,异常处理的一个优点是可以告诉异常(一个中央try块可以处理来自各个地方的各种异常/ try块可以处理某些类型的异常,让其他异常传播)。
此外,建议抛出其中一个标准异常或从其中一个类派生类。那么如果你只是想处理这个异常并且不关心这个特定的类型,那么你就可以只用catch (const std::exception&)
。
catch
确实不是必然需要确切的类型。
使用从std::exception
派生的例外(在<stdexcept>
中找到)是常见的和良好的做法。原因是,你可以多形地捕捉,即你做而不是需要知道确切的类型(另见Difference: std::runtime_error vs std::exception()),并且我们有一个约定来处理这个。
无论您使用的标准(例如:std::range_error
)提供者之一,或者如果没有适合您的问题[足够],专门std::exception
:
#include <stdexcept>
class moores_law_stopped : public std::exception {
public:
virtual ~moores_law_stopped() throw() {}
virtual const char *what() const throw() {
return "moores law stopped. duck under your table.";
}
};
#include <iostream>
int main() {
try {
throw moores_law_stopped();
} catch (std::exception const &e) {
std::cerr << "oh oh: " << e.what() << std::endl;
}
}
输出:
oh oh: moores law stopped. duck under your table.
的约定是通过引用或const引用来捕获的,这样就可以获得多态行为而不用担心object slicing。
发表100次:“我只会抛出派生自std :: exception的对象” –
@Tadeusz除了抛出一个'int'来终止一个程序的常见习语之外。 ('main'包含'try ... catch'来捕获int并返回它,这个习惯用法和调用'exit' **的效果相同,除了调用了所有局部变量的析构函数。 –
@JamesKanze:有趣的是,我不知道这个成语。我确实看到了一种从无到有继承的“SuicideException”,一次,我会猜你的角色。在这两种情况下,尽管你确实没有人写过“catch(...)”子句。 –