【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
首先可以把模板分为两类:函数模板以及类模板,其作用我觉得都是用来代替实际类型。
首先看函数模板:
其定义如下:
template <class type>//或者用typename作用是相同的
type 函数名(parameter list) { // 函数的主体 } //此处一般函数的返回类型与函数的形参都是前面所定义的那个类型,其作用是,函数实际调用时,type类可以被转换为其他类型。 例如:找到两个数的最大值:
#include <iostream>
#include <string>
using namespace std;
template <typename T>
inline T const& Max(T const& a, T const& b) {
return a < b ? b: a;
}
int main() {
int i = 39;
int j = 20;
cout << "Max(i,j)" << Max(i, j) << endl;
double f1 = 13.5;
double f2 = 20.7;
cout << "Max(f1,f2)" << Max(f1, f2) << endl;
string s2 = "Hello";
string s3 = "World";
cout << "Max(s1,s3)" << Max(s2, s3) << endl;
system("pause");
return 0;
}
另外一个是类模板;
其一般形式为:
template <class type>class 类名{
}
其作用也是用来代替类别中某些参数的定义类型;
例如:实现元素的入栈出栈
#include <iostream> #include <vector> #include <cstdlib> #include <string> #include <stdexcept> using namespace std; template <class T> class Stack { private : vector<T>elems; public: void push(T const&); void pop(); T top()const; bool empty()const { return elems.empty(); } }; template <class T> void Stack<T>::push(T const& elem) { elems.push_back(elem); } template<class T> void Stack<T>::pop(){ if (elems.empty()) { throw out_of_range("Stack<>::pop():empty stack"); //扔出来out of range 是exception 的子类所以能被catch } elems.pop_back(); } template <class T> T Stack<T>::top() const { if (elems.empty()){ throw out_of_range("Stack<>::top():empty stack"); } return elems.back(); } int main() { try { Stack<int> intStack; Stack<string> stringStack; intStack.push(7); cout << intStack.top() << endl; stringStack.push("hello"); cout << stringStack.top() << std::endl; stringStack.pop(); stringStack.pop(); } catch (exception const& ex) { cerr << "Exception:" << ex.what() << endl; return - 1; } system("pause"); }
其中empty()用来判断容器是否为空。
发现这个代码里面有一些我看不懂的地方,比如throw,比如catch,原来是我之前没有看异常处理这一部分的内容,我以为这一部分就是出了bug 怎么去处理呢,那肯定百度、Bing比较有效果啊.所以补上异常处理的内容:
例如:判断是不是三角形。此处采用了try-catch结构,throw出的值被catch(看的是类型)接收了,其中...表示所有类型,在有多个catch时,一般放在最后表示其他。
#include <iostream> #include <cmath> using namespace std; template <class T> inline T triangle(T a, T b, T c) { T s = (a + b + c) /2; if (a + b <= c || b + c <= a || c + a <= b)throw a; return sqrt(s*(s - a)*(s - b)*(s - c)); } int main() { int a, b, c; cin >> a >> b >> c; try { while (a > 0 && b > 0 && c > 0) { cout << triangle(a, b, c) << endl; cin >> a >> b >> c; } } catch (...) { cout << "a=" << a << ",b=" << b << ",c=" << c << ",that is not a trigle!" << endl; } cout << "end" << endl; system("pause"); return 0; }
另外一个程序
#include <iostream> using namespace std; int main() { void f1(); try { f1(); } catch (double) { cout << "ERROR0!" << endl;} cout << "end0" << endl; system("pause"); return 0; } void f1() { void f2(); try { f2(); } catch (char) { cout << "ERROR1!"; } cout << "end1" << endl; } void f2() { void f3(); try { f3(); } catch (int) { cout << "ERROR2!"; } cout << "end2" << endl; } void f3() { double a = 0; try { throw a; } catch (float) { cout << "ERROR3!" << endl;; } cout << "end3" << endl; }
这个程序里面跟我预测的不太一样,我之前以为,会出现end3 end2 end1 ERROR0 end0,但是却并不是如此,这里catch与当前异常信息不能匹配后,将信息直接抛给了上一级,而没有完全把函数执行完。如果f3()中改成catch(double),则在第一次就匹配了,之后就可以正常完成函数(但是不执行catch中的内容),因此结果为:ERROR3!end3 end2 end1 end0。如果再f3()函数中再加一个throw;则不仅本次检测到了,而且还将该异常信息再次抛出,然后被第一个检测到了,因此,出现的结果是: ERROR3! ERROR0! end0
以声明函数时,可以同时列出可能抛出的异常类型
double triangle(double ,double,double) throw(int, double ,float ,char);
下面是一个实例,抛出一个除以零的异常,并在 catch 块中捕获该异常。
#include <iostream> using namespace std; double division(int a, int b) { if( b == 0 ) { throw "Division by zero condition!"; } return (a/b); } int main () { int x = 50; int y = 0; double z = 0; try { z = division(x, y); cout << z << endl; } catch (const char* msg) //这里将前面throw来的字符串给幅值到了msg中 { cerr << msg << endl; } //因此在这里可以被直接输出 return 0; }
C++ 标准的异常
C++ 提供了一系列标准的异常,定义在 <exception> 中,我们可以在程序中使用这些标准的异常。它们是以父子类层次结构组织起来的,如下所示:

下表是对上面层次结构中出现的每个异常的说明:
异常 | 描述 |
---|---|
std::exception | 该异常是所有标准 C++ 异常的父类。 |
std::bad_alloc | 该异常可以通过 new 抛出。 |
std::bad_cast | 该异常可以通过 dynamic_cast 抛出。 |
std::bad_exception | 这在处理 C++ 程序中无法预期的异常时非常有用。 |
std::bad_typeid | 该异常可以通过 typeid 抛出。 |
std::logic_error | 理论上可以通过读取代码来检测到的异常。 |
std::domain_error | 当使用了一个无效的数学域时,会抛出该异常。 |
std::invalid_argument | 当使用了无效的参数时,会抛出该异常。 |
std::length_error | 当创建了太长的 std::string 时,会抛出该异常。 |
std::out_of_range | 该异常可以通过方法抛出,例如 std::vector 和 std::bitset<>::operator[]()。 |
std::runtime_error | 理论上不可以通过读取代码来检测到的异常。 |
std::overflow_error | 当发生数学上溢时,会抛出该异常。 |
std::range_error | 当尝试存储超出范围的值时,会抛出该异常。 |
std::underflow_error | 当发生数学下溢时,会抛出该异常。 |
定义新的异常
您可以通过继承和重载 exception 类来定义新的异常。下面的实例演示了如何使用 std::exception 类来实现自己的异常:
文中内容部分摘自菜鸟教程与谭浩强老师的C++教程。
来源:oschina
链接:https://my.oschina.net/u/4433424/blog/3148131