① 在上述继承体系中,每个类都有提供了构造函数、复制构造函数、和赋值操作符重载。
② logic_error类及其子类、runtime_error类及其子类,它们的构造函数是接受一个string类型的形式参数,用于异常信息的描述
③ 所有的异常类都有一个what()方法,返回const char* 类型(C风格字符串)的值,描述异常信息。
异常名称 | 描述 |
exception | 所有标准异常类的父类 |
bad_alloc | 当operator new and operator new[],请求分配内存失败时 |
bad_exception | 这是个特殊的异常,如果函数的异常抛出列表里声明了bad_exception异常,当函数内部抛出了异常抛出列表中没有的异常,这是调用的unexpected函数中若抛出异常,不论什么类型,都会被替换为bad_exception类型 |
bad_typeid | 使用typeid操作符,操作一个NULL指针,而该指针是带有虚函数的类,这时抛出bad_typeid异常 |
bad_cast | 使用dynamic_cast转换引用失败的时候 |
ios_base::failure | io操作过程出现错误 |
logic_error | 逻辑错误,可以在运行前检测的错误 |
runtime_error | 运行时错误,仅在运行时才可以检测的错误 |
异常名称 | 描述 |
length_error | 试图生成一个超出该类型最大长度的对象时,例如vector的resize操作 |
domain_error | 参数的值域错误,主要用在数学函数中。例如使用一个负值调用只能操作非负数的函数 |
out_of_range | 超出有效范围
|
invalid_argument | 参数不合适。在标准库中,当利用string对象构造bitset时,而string中的字符不是’0’或’1’的时候,抛出该异常 |
异常名称 | 描述 |
range_error | 计算结果超出了有意义的值域范围 |
overflow_error | 算术计算上溢 |
underflow_error | 算术计算下溢 |
invalid_argument | 参数不合适。在标准库中,当利用string对象构造bitset时,而string中的字符不是’0’或’1’的时候,抛出该异常 |
示例代码:
- #define _CRT_SECURE_NO_WARNINGS
- #include <iostream>
- using namespace std;
- #include <stdexcept> // 标准异常
-
- class num_1
- {
- public:
- int age;
-
- num_1(int age)
- {
- if(age<0 || age>150)
- {
- throw length_error("年龄有错误");
- }
- }
- };
-
- int main(void)
- {
- try
- {
- num_1 p1(1112);
- }
- catch(exception &p2)
- {
- cout << "类型异常,异常类为:" << p2.what() << endl;
- }
- return 0;
- }
在代码中,定义了一个类num_1,其中有一个构造函数,用于判断年龄是否符合要求,并抛出标准异常length_error。在主函数中,通过使用try-catch语句来捕获并处理异常。如果捕获到异常,会输出异常类的信息。通过这种方式可以处理并控制程序中的异常情况。
① 标准库中的异常是有限的;
② 在自己的异常类中,可以添加自己的信息。(标准库中的异常类值允许设置一个用来描述异常的字符串)。
① 建议自己的异常类要继承标准异常类。因为C++中可以抛出任何类型的异常,所以我们的异常类可以不继承自标准异常,但是这样可能会导致程序混乱,尤其是当我们多人协同开发时。
② 当继承标准异常类时,应该重载父类的what函数。
因为我们自己编写的异常类要继承自 exception 这个标准异常类,所以我们应该有一种思路就是使用多态来扩展,多态的好处就是不影响原基类的情况下进行安全扩展。
我们来到 exception 类的定义:
- virtual const char*
- what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW;
可以看到标准异常类也为多态做好了准备,做了一个virtual的虚函数。注意这里返回的是char* 类型的数组。
第一步先写一个继承类,继承自exception。
代码如下:
- class num_1:public exception //自己写的异常类
- {
- private:
- string msg;
-
- public:
- num_1(string msg)
- {
- this->msg = msg;
- }
- virtual const char *what() // 记得这里的返回值是char*
- {
- return this->msg.c_str(); // .c_str()作用是类型转换,即string——>char*
- }
- };
第二步做了一个普通的类,并在异常处使用 throw 抛出异常类 num_1。
代码如下:
- class num_2 //普通类,进行年龄判断
- {
- public:
- int age;
-
- num_2(int age)
- {
- if(age<0 || age>160)
- {
- if(age<0)
- {
- throw num_1("年龄小于0,异常"); //抛异常
- }
- else
- {
- throw num_1("年龄大于160,异常"); //抛异常
- }
-
- }
- else
- {
- this->age = age;
- }
- }
- };
第三步,在 main 函数中进行。
代码如下:
- try
- {
- num_2 p1(180);
- }
- catch (exception &e) // 相当于exception &e = num_1("年龄大于160,异常") 符合多态条件
- {
- cout << e.what() << endl;
- }
总体代码:
- #include <cmath>
- #include <cstdlib>
- #include <cstring>
- #include <ctime>
- #include <iostream>
- #include <string>
- #include<iomanip>
- #include<fstream> //头文件流
- #include<vector>
- using namespace std;
-
-
- class num_1:public exception //自己写的异常类
- {
- private:
- string msg;
-
- public:
- num_1(string msg)
- {
- this->msg = msg;
- }
- virtual const char *what() // 记得这里的返回值是char*
- {
- return this->msg.c_str(); // .c_str()作用是类型转换,即string——>char*
- }
- };
-
- class num_2
- {
- public:
- int age;
-
- num_2(int age)
- {
- if(age<0 || age>160)
- {
- if(age<0)
- {
- throw num_1("年龄小于0,异常");
- }
- else
- {
- throw num_1("年龄大于160,异常");
- }
-
- }
- else
- {
- this->age = age;
- }
- }
- };
-
- int main(void)
- {
- try
- {
- num_2 p1(180);
- }
- catch (num_1 &e) // exception &e = num_1("年龄大于160,异常")
- {
- cout << e.what() << endl;
- }
- return 0;
- }