c++ 模板与异常处理学习

ぐ巨炮叔叔 提交于 2019-12-27 14:51:08

【推荐】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++教程。

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!