异常处理
异常: 程序执行过程中发生的一些不希望发生的事。
传统解决方法: 在错误发生处就地处理。
好处:程序员阅读代码可以直接看到错误情况。
问题:因为错误污染代码使理解和维护变得困难。
异常处理机制:分为异常抛出,以及异常捕获和处理两个部分。
异常抛出
作用: 发生异常情况时将包含出错信息的对象抛出当前环境,发送给更大的环境得到更好的处理。
格式: throw 异常对象;
过程: 生成并初始化 throw 对象的副本,传回调用它的函数,退出函数,回收所有局部对象。类似函数的 return 过程。
捕获异常
catch 捕获异常: catch (<捕获的异常类型><可选对象>) { //异常处理代码 } 注意: 捕获以类型为标志,是否省略对象取决于需不需要在处理过程中引用该对象。 catch (...) 可以捕获任意类型的异常。 抛出-捕获格式: try { //可能抛出异常的代码 } catch (类型1 对象1) { //处理情况1的代码 } catch (类型2 对象2) { //处理情况2的代码 } #include <iostream> #include <cmath> using namespace std; class DivideByZeroException { private: const char *message; public: DivideByZeroException() : message("case 1") {} const char *what() { return message; } }; int main() { int a, b; try { cin >> a >> b; if (b == 0) { throw DivideByZeroException(); } cout << a / b; } catch (const char *) { cout << "case 2\n"; } catch (DivideByZeroException) { cout << "case 3\n"; } catch (...) { cout << "case 4\n"; } return 0; } 输入:100 0 正确答案: case 3 2. 以下是一段带异常处理的除法计算器,请按照规范的异常处理过程补全它。(空1) #include <iostream> #include <cmath> using namespace std; class DivideByZeroException { private: _____(1)_____; public: DivideByZeroException() : message("attempt to divide by zero") {} const char *what() { return message; } }; double Div(int x, int y) { if (_____(2) _____) _____(3)_____; return 1.0 * x / y; } int main() { int number1, number2; double result; cout << "Enter two integers (end-of-file to end): "; while (cin >> number1 >> number2) { try { result = Div(number1, number2); cout << "The quotient is: " << result << endl; } catch (_____(4) _____ ex) { cout << "Exception occurred: " << _____(5) _____ << '\n'; } cout << "\nEnter two integers (end-of-file to end): "; } cout << endl; } 答案解释 const char* message 答案解释 y == 0 4. (3) 答案解释 throw DivideByZeroException(); 5. (2) 答案解释 DivideByZeroException 6. (5) 答案解释 ex.what()
异常规格说明
传统函数声明:
void f(); //函数可以抛出任何异常 带异常规格的函数声明: void f() throw(); //函数不会有异常抛出。 void f() throw(toobig, toosmall, divzero); //函数会抛出toobig, toosmall, divzero三种异常。 通用格式为 返回类型 函数名(形式参数表) throw(异常类型); C++11 的改进 摒弃异常规格声明。 关键字 noexcept,void f() noexcept; 表示函数不抛出。 运算符 noexcept 判断表达式是否会抛异常。 1. 读程序,写结果。 #include <iostream> using namespace std; class up{}; class down{}; void f(int i) throw(up, down); int main() { for (int i = 1; i <= 10; ++i) try { f(i); } catch (up) { cout << "up catched" << endl; } catch (down) { cout << "down catched" << endl; } return 0; } void f(int i) throw(up, down) { if (i % 3 == 0) throw up(); if (i % 4 == 0) throw down(); } 正确答案: up catched down catched up catched down catched up catched
类模板
类模板的定义格式:
template <模板的形式参数表> class 类名{...};
模板的形式参数可以是类型形参(用关键字class或typename开始,后面是形式参数名)和非类型形参。
在类定义外面定义成员函数格式:
template <模板的形式参数表> 返回类型 类名<各形式参数>::函数名(形式参数表)
填空题 1. 类模板A的声明如下。若要在类定义外定义f()函数,需要如何实现?请给出除函数体外的代码(函数体内用/*函数体*/代替)。 template <class T, typename U> class A { public: T a, b; U f(const T &a, const T &b); }; 答案解释 template <class T, typename U> U A::f() { /*函数体*/ }
类模板的实例化
类模板对象的实例化格式:
类模板名<模板的实际参数表> 对象表;
填空题 1. stl中的std::map的定义是 template < class Key, // map::key_type class T, // map::mapped_type class Compare = less<Key>, // map::key_compare class Alloc = allocator<pair<const Key,T> > // map::allocator_type > class map; 以下实例化正确的有:(按照大写字母从小到大排列无空格填写) A. std::map<std::string,int> B. std::map<"abcd",int> C. std::map<int,std::string> D. std::map<7,'c'> 正确答案: AC