C++ 异常机制(下)
八、C++标准异常类
C++标准库异常类继承层次中的根类为exception,其定义在exception头文件中,它是C++标准库所有函数抛出异常的基类,exception的接口定义如下:
namespace std {
class exception {
public:
exception() throw(); //不抛出任何异常
exception(const exception& e) throw();
exception& operator= (const exception& e) throw();
virtual ~exception() throw)();
virtual const char* what() const throw(); //返回异常的描述信息
};
}
先来看一下 exception 类的直接派生类:
异常名称 | 说 明 |
---|---|
logic_error | 逻辑错误。 |
runtime_error | 运行时错误。 |
bad_alloc | 使用 new 或 new[ ] 分配内存失败时抛出的异常。 |
bad_typeid | 使用 typeid 操作一个 NULL 指针,而且该指针是带有虚函数的类,这时抛出 bad_typeid 异常。 |
bad_cast | 使用 dynamic_cast 转换失败时抛出的异常。 |
ios_base::failure | io 过程中出现的异常。 |
bad_exception | 这是个特殊的异常,如果函数的异常列表里声明了 bad_exception 异常,当函数内部抛出了异常列表中没有的异常时,如果调用的 unexpected() 函数中抛出了异常,不论什么类型,都会被替换为 bad_exception 类型。 |
logic_error 的派生类:
异常名称 | 说 明 |
---|---|
length_error | 试图生成一个超出该类型最大长度的对象时抛出该异常,例如 vector 的 resize 操作。 |
domain_error | 参数的值域错误,主要用在数学函数中,例如使用一个负值调用只能操作非负数的函数。 |
out_of_range | 超出有效范围。 |
invalid_argument | 参数不合适。在标准库中,当利用string对象构造 bitset 时,而 string 中的字符不是 0 或1 的时候,抛出该异常。 |
runtime_error 的派生类:
异常名称 | 说 明 |
---|---|
range_error | 计算结果超出了有意义的值域范围。 |
overflow_error | 算术计算上溢。 |
underflow_error | 算术计算下溢。 |
九、编写自己的异常类
原则:建议继承标准异常类,并重载父类的what函数和析构函数
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include<stdexcept>
using namespace std;
class Person {
public:
Person() {
mAge = 0;
}
void setAge(int age) {
if (age < 0 || age > 100) {
throw out_of_range("年龄应该在0-100之间!");
}
this->mAge = age;
}
public:
int mAge;
};
//test01()使用标准库的异常类,下面的exception可以换为out_of_range
void test01() {
Person p;
try {
p.setAge(1000);
}
catch (exception e) {
cout << e.what() << endl;
}
}
//自己写个异常类,重载父类的what函数和析构函数
class MyOutOfRange : public exception {
public:
MyOutOfRange(const char* error) {
pError = new char[strlen(error) + 1];
strcpy(pError, error);
}
~MyOutOfRange() {
if (pError != NULL) {
delete[] pError;
}
}
virtual const char* what() const {
return pError;
};
public:
char* pError;
};
void fun02() {
throw MyOutOfRange("我自己的out_of_range!");
}
void test02() {
try {
fun02();
}
catch (exception& e) {
cout << e.what() << endl;
}
}
int main(void)
{
test01();//结果:年龄应该在0-100之间!
//test02();//结果:我自己的out_of_range!
return 0;
}
十、继承在异常中的应用
异常尽量抛个类对象(基类),不要再用 -1 或 char* 。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
//异常基类
class BaseMyException {
public:
virtual void what() = 0;
virtual ~BaseMyException() {}
};
class TargetSpaceNullException : public BaseMyException {
public:
virtual void what() {
cout << "目标空间空!" << endl;
}
~TargetSpaceNullException() {}
};
class SourceSpaceNullException : public BaseMyException {
public:
virtual void what() {
cout << "源空间为空!" << endl;
}
~SourceSpaceNullException() {}
};
void copy_str(char* taget, char* source) {
if (taget == NULL) {
throw TargetSpaceNullException();
}
if (source == NULL) {
throw SourceSpaceNullException();
}
//int len = strlen(source) + 1;
while (*source != '\0') {
*taget = *source;
taget++;
source++;
}
}
int main(void) {
const char* source = "abcdefg";
char buf[1024] = { 0 };
try {
copy_str(buf, NULL);
}
catch (BaseMyException& ex) {
ex.what();
}
cout << buf << endl;
return 0;
}
//结果:源空间为空!