390 likes | 511 Views
国家级精品课程网站 (本书配套教学网站) http://programming.xjtu.edu.cn. 第 13 章 模板与异常处理. 13.1 模板 13.2 异常处理机制 13.3 友元 程序设计举例. 13.1 模板. 一、函数模板 1 、定义格式: template << 模板参数表 >> < 类型 > < 函数名 >(< 参数表 >) { … }. 2 、说明
E N D
国家级精品课程网站(本书配套教学网站)http://programming.xjtu.edu.cn国家级精品课程网站(本书配套教学网站)http://programming.xjtu.edu.cn
第13章 模板与异常处理 • 13.1 模板 • 13.2 异常处理机制 • 13.3 友元 • 程序设计举例
13.1 模板 • 一、函数模板 • 1、定义格式: • template <<模板参数表>> • <类型> <函数名>(<参数表>) • { • … • }
2、说明 • (1)<模板参数表>中的模板参数的形式为class <类型参数>,这里关键字class与一般所讲的类无关,而是与<类型参数>一起说明这是一个内部类型或用户自己定义的数据类型。 • (2)在使用模板函数时,模板中的类型参数可用一个实际类型替换,从而达到了类型通用的目的。 • (3)当类型参数的含义确定后,编译器将以函数模板为样板,生成一个函数。
[例12-1]求两个数最大值的函数模板 • #include <iostream> • #include <string> • using namespace std; • template <class T> • T Max(T a, T b) • { • return a>b?a:b; • }
// 测试用主函数 • int main() • { • int i1 = 3, i2 = 5; • double d1 = 3.3, d2 = 5.2; • string str1("xjtu"), str2("xian"); • cout << "Type int: " << Max(i1, i2) << endl; • cout << "Type double: " << Max(d1, d2) << endl; • cout << "Type string: " << Max(str1, str2) << endl; • return 0; • }
3、使用函数模板的注意事项 • (1)在函数模板的参数表中,至少有一个参数的类型为模板的类型参数。另外,函数的返回值的类型也可以是该类型参数。 • (2)模板中可以带有多个参数类型。 • 例如: • template <class T1, class T2, class T3> • void func1(T1 arg1,T2 arg2, T3 arg3) • { • … • }
(3)函数可以带有模板参数表中未给出的、已存在的数据类型的参数。(3)函数可以带有模板参数表中未给出的、已存在的数据类型的参数。 • 例如: • template <class T> • T func2(T arg1,int arg2) • { • … • }
二、类模板 • 1、类是对问题空间的抽象,而类模板则是对类的抽象,即更高层次上的抽象。 • 2、程序中可以首先定义一个类模板,然后通过使用不同的实参生成不同的类。 • 3、类模板的定义格式: • template <class <类型参数>> • class <类名> • { • …… • };
例13-2定义一个任意类类型AnyType • #include <iostream> • using namespace std; • template <class T> • class AnyType • { T x, y; • public: • AnyType(T a, T b): x(a), y(b){} • T GetX(){return x;} • T GetY(){return y;} • };
// 测试用主函数 • int main() • { AnyType <int> i (1, 2); • AnyType <double> d (1.5, 2.7); • AnyType <char> c ('a', 'b'); • AnyType <char *> s ("Hello", "template class"); • cout << "整型类:" << i.GetX() << ", " << i.GetY() << endl; • cout << "双精度类:" << d.GetX() << ", " << d.GetY() << endl; • cout << "字符类:" << c.GetX() << ", " << c.GetY() << endl; • cout << "字符串类:" << s.GetX() << ", " << s.GetY() << endl; • return 0; • }
13.2 异常处理机制 • 异常处理机制的作用: • 使程序可以向更高的层次传递意想不到的事件 • 使程序能更好地从异常事件中恢复过来。 • 异常处理由三个语句实现 • 1. 异常处理的语句 • (1) throw • 用来检测是否产生异常,若是,则抛掷异常。 • 格式: throw 表达式;
(2) try • 是一个复合语句块,它将那些有可能产生异常的语句框定在try块中,并根据异常的情况使用不同的throw表达式抛出异常。 • try { //复合语句 • …… • throw 表达式1; • …… • throw 表达式n; • }
(3)catch • catch块中放置异常处理的语句 • 每个catch块是一个复合语句,处理相应的异常。 • 格式: • catch(异常类型说明1) • { ......//复合语句 • }
例13-3: 使用异常处理机制 • 使用异常处理机制,检查小学生年龄是否正确,要求能够处理年龄小于0岁和大于20岁的异常情况。 • #include <iostream> • using namespace std; • void testfun(int StudentAge) • {
try • { • if(StudentAge < 0) • throw "输入的学生年龄必须是正整数!"; • if(StudentAge > 20) • throw StudentAge; • cout << "学生年龄是:" << StudentAge <<endl; • }
catch(int i) • { cout << "发生异常:学生年龄是" << i <<"岁,太大了!" << endl; • } • catch(const char* Message) • { cout << "发生异常:" << Message <<endl; • } • }
int main() • { • testfun(12); // 年龄12岁,未发生异常 • testfun(-9); // 年龄-9岁,发生异常 • testfun(77); // 年龄是77岁,发生异常 • return 0; • }
13.3 友元 • 允许类外部的函数或者类具有该类私有成员的特权。 • 一、友元函数 • 一个类的友元函数是在该类中说明的、用关键字friend修饰的函数,该函数有权访问类中所有的成员。 • 说明一个友元的一般形式为 • friend <类型> <函数名>(<参数表>);
例如: • class Person • { ...... • public: • friend void FriFunc(Person& person); • ... ... • }; • void FriFunc(Person &person) • { ...... • } • 一个类的友元可以是类外的任何函数,包括不属于任何类的函数和属于某个类的成员函数。
二、友元类 • 当一个类成为另一个类的友元时,就构成了友元类。这意味着该类的每一个成员函数都是另一个类的友元函数。如: • class Person • { • ...... • public: • friend class Government; • ... ... • };
程序设计举例 • 定义一个求指数为正整数的幂函数的函数模板,并测试之。 • // Example 13-4:指数为正整数的幂函数模板 • #include <iostream> • using namespace std; • template <class T> • T Power(T a, int exp) • { • T ans = a; • while(--exp>0) ans*=a; • return ans; • }
// 测试用主函数 • int main() • { • cout << "3^5= " <<Power(3, 5) << endl; • cout << "1.1^2= " << Power(1.1, 2) << endl; • return 0; • }
例 13-5: 顺序查找算法 • #include <iostream> • using namespace std; • template <class T> • int sequentialsearch(T a[], const T& k, int n) • { • int i=0; • while(k!=a[i]&&i<=n-1) • i++; • if(i>n-1)i=-1; • return i; • }
// 测试用主函数 • int main() • { • int i1[] ={3, 2, 5, 0, -1, 7}; • double d1[] ={3.3, 2.1, 0.3, 1.5, 10.6, 5.2}; • char *c1="xjtu"; • cout <<sequentialsearch(i1, 15, 6)<< endl; • cout <<sequentialsearch(d1, 3.3, 5)<< endl; • cout <<sequentialsearch(c1, 'j', 4)<< endl; • return 0; • }
例13-6:通用的栈类 • #include <iostream> • using namespace std; • template <class T, int n = 10> • class AnyStack • { T m_tStack[n]; • int m_nMaxElement; • int m_nTop; • public: AnyStack() : m_nMaxElement(n), m_nTop(0){} • int GetTop() {return m_nTop;} • bool Push(T); //入栈函数 • bool Pop(T&); //出栈函数 • };
template <class T, int n> • bool AnyStack <T, n>::Push(T elem) • { • if(m_nTop<=m_nMaxElement) • { • m_tStack[m_nTop] = elem; • m_nTop++; • return true; • } • else • return false; • }
template <class T, int n> • bool AnyStack <T, n>::Pop(T &elem) • { • if(m_nTop > 0) • { • m_nTop--; • elem = m_tStack[m_nTop]; • return true; • } • else • return false; • }
// 测试用主函数 • int main() • { • int n; • char * s1; • AnyStack <int> iStack; //定义一个整数栈 • iStack.Push(5); • iStack.Push(6); • iStack.Pop(n); • cout << "第一个出栈整数= " << n << endl; • iStack.Pop(n);
cout << "第二个出栈整数= " << n << endl; • AnyStack <char *> strStack; //定义一个字符串栈 • strStack.Push("It's first string"); • strStack.Push("It's second string"); • strStack.Pop(s1); • cout << "第一个出栈字符串=" << s1 << endl; • strStack.Pop(s1); • cout << "第二个出栈字符串=" << s1 << endl; • return 0; • } • 除0异常。
//Example 13-7: 除0异常 • #include <iostream> • using namespace std; • double Div(double a, double b);
// 测试用主函数 • int main() • { double n1, n2, result; • cout<<"Input two numbers(other characters will terminate the program):"<<endl; • while(cin>>n1>>n2) • { • try • { result=Div(n1,n2); • cout<<n1<<"/"<<n2<<"="<<result<<endl; • }
catch(double) • { • cout<<" Exception occurred: attempted to divide by zero."<<endl; • } • cout<<"Input two numbers(other characters will terminate the program):"<<endl; • } • cout<<"That is ok."<<endl; • return 0; • }
double Div(double a, double b) • { • if(b==0.0) • throw b; • return a/b; • }
例13-8 解一元二次方程 • 求一元二次方程ax2+bx+c=0的根,其中系数a、b、c均为实数,其数值由键盘输入。要求使用异常处理机制。 • //Example: • #include <iostream> • #include <cmath> • using namespace std; • void Root(double a,double b,double c) • { • double x1, x2, delta; • delta=b*b-4*a*c;
if(a==0) throw "divide by zero"; • if(delta<0) throw 0; • x1=(-b+sqrt(delta))/(2*a); • x2=(-b-sqrt(delta))/(2*a); • cout<<"x1="<<x1<<endl<<"x2="<<x2<<endl; • }
int main( ) • { double a, b, c; • cout << "please input a, b, c = ? "; • cin >> a >> b >> c; • try • { Root(a,b,c); • }
catch(char *) • { cout<<" Exception occurred: it is not a quadratic equation. "<<endl; • } • catch(int) • { cout<<" Exception occurred: the real root of this equation does not exist. "<<endl; • } • return 0; • }
结 束 语 • 学好计算机的唯一途径是 • 你的编程能力与你在计算机上投入的时间成 上机练习 正比