模板

模板函数

1
2
3
4
5
6
7
8
9
10
11
12
13
template <class 类型参数>
返回类型 函数名(模板形参表)
{
函数体
}
//下面的形式也被接受
template<typename 类型参数>
返回类型 函数名(模板型参表)
{
函数体
}
//函数模板调用方式
函数名(实参数表);
  • 在函数模板中允许使用多个类型的参数,template定义部分的每个模板参数前必须有关键字class

    1
    2
    3
    4
    5
    6
    7
    #include <iostream.h>  //C++IO流头文件
    //定义两个参数的函数模板
    template<class type1, class type2>
    void myfunc(type1 x, type2 y)
    {
    cout<<x<< “ “ << y<<endl;
    }
  • 在template语句与函数模板定义语句之间不允许有别的语句

    1
    2
    3
    4
    5
    6
    template<class T>
    int i; //编译错误,不允许有别的语句
    T max(T x, T y)
    {
    return (x>y)?x:y;
    }
  • 函数可以带有模板参数表中未给出的、已存在的数据类型的参数。

  • 实例化T的各模板之间必须保持完全的一致,否则会发生错误。发生错误时,解决方案为采用强制类型转换,或用非模板函数重载函数模板。

    • 声明一个非模板函数的原型,例如

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      template<class T>
      T max(T x, T y)
      {
      return (x>y)?x:y;
      }
      int max(int, int);//只声明一个非模板函数的原型
      void func(int i,char c)
      {
      max(i, i); //正确 ,调用max(int,int)
      max(c, c); //正确 ,调用max(char,char)
      max(i, c); //正确 ,调用 max(int,int),使用隐式类型转换
      max(c, i); //正确 ,调用max(int,int),使用隐式类型转换
      }
    • 定义一个完整的非模板函数重载模板函数,比如:在上面程序的模板定义下面定义如下函数:

      1
      2
      3
      4
      char *max(char *x, char *y)
      {
      return (strcmp(x,y)>0)?x:y;
      }
  • 重载模板函数调用顺序

    • 寻找一个参数完全匹配的函数,如果找到就调用它。
    • 寻找一个函数模板,将其实例化,产生一个匹配的模板函数。若找到了,就调用它。
    • 尝试低一级的对函数的重载方法。例如通过类型转换可产生参数匹配等,若找到了,就调用它。

类模板

1
2
3
4
5
6
7
8
9
10
11
12
13
template <class Type>
class ClassName
{
//具体内容
};
//下面的形式也被接受
template <typename Type>
class ClassName
{
//具体内容
};
//模板类调用形式
ClassName<类型实参表> object;

在类定义体外定义成员函数时,若此成员函数中有类型参数存在,则需要在函数体外进行模板声明,并且在函数名前的类名后缀上“”。

  • 在每个类模板定义之前,都需要在前面加上模板声明,如:

    1
    template<class type>

    类模板在使用的时候,必须在名字后面缀上模板参数<type>,例如stack<int>

  • 模板类可以有多个模板参数

  • 考试中遇到模板考虑填写<>

异常处理

  • try块和catch块作为一个整体出现,catch块是try-catch结构中的一部分,必须紧跟在try块之后,不能单独使用,在二者之间也不能插入其他语句。但是在一个try-catch结构中,可以只有try块而无catch块。即在本函数中只检查而不处理,把catch处理块放在其他函数中。

  • try和catch块中必须有用花括号括起来的复合语句,即使花括号内只有一个语句,也不能省略花括号。

  • 一个try-catch结构中只能有一个try块,但却可以有多个catch块,以便与不同的异常信息匹配。

  • catch还可以有另外一种写法,即除了指定类型名外,还指定变量名,如

    1
    catch(double d)

    此时如果throw抛出的异常信息是double型的变量a,则catch在捕获异常信息a的同时,还使d获得a的值,或者说d得到a的一个拷贝。

  • 如果在catch子句中没有指定异常信息的类型,而用了删节号“…”,则表示它可以捕捉任何类型的异常信息.这种catch子句应放在try-catch结构中的最后,相当于“其他”。如果把它作为第一个catch子句,则后面的catch子句都不起作用。

  • try-catch结构可以与throw出现在同一个函数中,也可以不在同一函数中。当throw抛出异常信息后,首先在本函数中寻找与之匹配的catch,如果在本函数中无try-catch结构或找不到与之匹配的catch,就转到离开出现异常最近的try-catch结构去处理。

  • 某些情况下,在throw语句中可以不包括表达式,如

    1
    throw;//表示“我不处理这个异常,请上级处理”。
  • 如果throw抛出的异常信息找不到与之匹配的catch块,那么系统就会调用一个系统函数terminate,使程序终止运行。

  • 如果想声明一个不能抛出异常的函数,可以写成以下形式:

    1
    double triangle(double,double,double) throw();//throw无参数
  • 在异常处理中,try中的局部对象会被析构,析构对象的顺序与构造的顺序相反,然后执行与异常信息匹配的catch块中的语句。

命名空间

1
2
3
4
5
6
7
8
9
//简化命名空间
//方法1
namespace Television//声明命名空间,名为Television
{…}
//可以用一个较短而易记的别名代替它。如
namespace TV = Television;//别名TV与原名Television等价
//方法2
using ns1::Student;
//using声明的有效范围是从using语句开始到using所在的作用域结束