一、异常与继承
如果异常类型为C++的类,并且该类有其基类,则应该将派生类的错误处理程序放在前面,基类的错误处理程序放在后面。(否者派生类的异常会被基类类型捕获,而异常要求每种类型捕获对应类型的异常)
示例:
#include <iostream>
#include <string>
using namespace std;
class MyException
{
public:
MyException(const char* message)
: message_(message)
{
cout<<"MyException ..."<<endl;
}
MyException(const MyException& other) : message_(other.message_)
{
cout<<"Copy MyException ..."<<endl;
}
virtual ~MyException()
{
cout<<"~MyException ..."<<endl;
}
const char* what() const
{
return message_.c_str();
}
private:
string message_;
};
class MyExceptionD : public MyException
{
public:
MyExceptionD(const char* message)
: MyException(message)
{
cout<<"MyExceptionD ..."<<endl;
}
MyExceptionD(const MyExceptionD& other)
: MyException(other)
{
cout<<"Copy MyExceptionD ..."<<endl;
}
~MyExceptionD()
{
cout<<"~MyExceptionD ..."<<endl;
}
};
int main(void)
{
try
{
MyExceptionD e("test exception");
throw e;//调用拷贝构造函数
}
catch (MyExceptionD& e)
{
cout<<"catch MyExceptionD ..."<<endl;
cout<<e.what()<<endl;
}
//如果基类异常放在前面,会将MyExceptionD异常当成MyException异常来处理
catch (MyException& e)
{
cout<<"catch MyException ..."<<endl;
cout<<e.what()<<endl;
}
return 0;
}
二、异常与指针
抛出指针通常是一个坏主意,因为抛出指针要求在对应处理代码存在的任意地方都存在指针所指向的对象(注意此时throw抛出时复制的是指针本身,不会去复制指针指向的内容)。
示例:
#include <iostream>
#include <string>
using namespace std;
class MyException
{
public:
MyException(const char* message)
: message_(message)
{
cout<<"MyException ..."<<endl;
}
MyException(const MyException& other) : message_(other.message_)
{
cout<<"Copy MyException ..."<<endl;
}
virtual ~MyException()
{
cout<<"~MyException ..."<<endl;
}
const char* what() const
{
return message_.c_str();
}
private:
string message_;
};
class MyExceptionD : public MyException
{
public:
MyExceptionD(const char* message)
: MyException(message)
{
cout<<"MyExceptionD ..."<<endl;
}
MyExceptionD(const MyExceptionD& other)
: MyException(other)
{
cout<<"Copy MyExceptionD ..."<<endl;
}
~MyExceptionD()
{
cout<<"~MyExceptionD ..."<<endl;
}
};
int main(void)
{
try
{
//MyExceptionD e("test exception");
//throw &e; //抛出后,栈对象被销毁,e变成悬挂指针
throw new MyExceptionD("test exception");
}
catch (void* e)//抛出的任何类型指针异常都成被void*捕获
{
cout<<"catch void* ..."<<endl;
cout<<((MyExceptionD*)e)->what()<<endl;
delete e;
}
catch (MyExceptionD* e)
{
cout<<"catch MyExceptionD ..."<<endl;
cout<<e->what()<<endl;
delete e;
}
catch (MyException& e)
{
cout<<"catch MyException ..."<<endl;
cout<<e.what()<<endl;
}
return 0;
}
三、异常规格说明
- 异常规格说明的目的是为了让函数使用者知道该函数可能抛出的异常有哪些。
- 可以在函数的声明中列出这个函数可能抛掷的所有异常类型。
例如:void fun() throw(A,B,C,D);
- 若无异常接口声明,则此函数可以抛掷任何类型的异常。
- 不抛掷任何类型异常的函数声明如下:
void fun() throw();
示例:
#include <iostream>
#include <string>
using namespace std;
class MyException
{
public:
MyException(const char* message)
: message_(message)
{
cout<<"MyException ..."<<endl;
}
MyException(const MyException& other) : message_(other.message_)
{
cout<<"Copy MyException ..."<<endl;
}
virtual ~MyException()
{
cout<<"~MyException ..."<<endl;
}
const char* what() const
{
return message_.c_str();
}
private:
string message_;
};
class MyExceptionD : public MyException
{
public:
MyExceptionD(const char* message)
: MyException(message)
{
cout<<"MyExceptionD ..."<<endl;
}
MyExceptionD(const MyExceptionD& other)
: MyException(other)
{
cout<<"Copy MyExceptionD ..."<<endl;
}
~MyExceptionD()
{
cout<<"~MyExceptionD ..."<<endl;
}
};
void fun(int n) throw (int, MyException, MyExceptionD)
{
if (n == 1)
{
throw 1;
}
else if (n == 2)
{
throw MyException("test exception1");
}
else if (n == 3)
{
throw MyExceptionD("test exception2");
}
else
throw 1.0;
}
//warning C4297: “fun2”: 假定函数不引发异常,但确实发生了
void fun2() throw()
{
throw 1;
}
int main(void)
{
try
{
fun(3);
//fun2();
}
catch (double d)
{
cout<<"catch double ..."<<endl;
cout<<"d="<<d<<endl;
}
catch (int n)
{
cout<<"catch int ..."<<endl;
cout<<"n="<<n<<endl;
}
catch (MyException& e)
{
cout<<"catch MyExceptionD ..."<<endl;
cout<<e.what()<<endl;
}
catch (MyExceptionD& e)
{
cout<<"catch MyException ..."<<endl;
cout<<e.what()<<endl;
}
return 0;
}
四、C++标准库异常层次