- 普通函数、lambda表达式、函数模板和模板实例函数都可以定义异常接口
- 指针和引用类型的异常都可以支持多态
catch
的子类异常一定要写在父类异常的上面,catch
执行后就不会再执行后面的catch
语句了- 对于指针异常,如果不打算向上抛出,一定要记得
delete
const volatile void *
可以捕获抛出的任何指针异常...
可以捕获抛出的任何异常- 不引发任何异常,在函数后面添加
throw()
、throw(void)
、noexcept
- 建议将
noexcept
应用到任何绝不允许异常传播到调用堆栈的函数,当函数被声明为noexcept
时,它使编译器可以在多种不同的上下文中生成更高效的代码
Exception.h
struct A {
int a = 1;
virtual int getA()const { return a; }
};
struct B : A
{
int a = 2;
int getA()const override { return a; }
};
#define cout cout<<__FILE__<<":"<<__LINE__<<": Exception: "
void testException() {
try
{
// 抛出子类指针类型的异常
//throw new B;
// 抛出子类对象类型的异常
throw B();
}
catch (const A e)
{
cout << e.getA() << endl;
throw; // 继续向上抛出异常,抛出的仍是原始的异常对象或指针
// 这里抛出的仍然是 B 类型的对象,而不是 e
}
catch (const A* e) // 与 catch (const A& e) 效果相同
{
cout << e->getA() << endl;
throw; // 继续向上抛出指针类型的异常,所以可以不 delete
}
catch (const B e) {
cout << e.getA() << endl;
}
catch (const B* e)
{
cout << e->getA() << endl;
delete e; // 不向上抛出,需要 delete 指针,以免内存泄漏
}
}
main.cpp
#include "Exception.h"
int main()
{
try
{
testException();
}
catch (const B e) {
cout << e.getA() << endl;
}
catch (const B* e) {
cout << e->getA() << endl;
delete e;
}
catch (const A e) {
cout << e.getA() << endl;
}
catch (const A* e) {
cout << e->getA() << endl;
delete e;
}
catch (...)
{
cout << "...\n";
}
return 0;
}
输出:
C:\ExceptionTest.h:27: Exception: 1
C:\main.cpp:95: Exception: 2