• 普通函数、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