C++类模板(泛型编程二)

来源:互联网 发布:苏轼 柳永 知乎 编辑:程序博客网 时间:2024/05/21 09:23

1.类模板定义

  a.类模板以相同的方式处理不同的类型;
  
  b.在类声明前使用template进行标识。

2.类模板语法规则

template <typename T>class Operator{public:    T op(T a, T b);};<typename T> 用于说明类中使用的泛指类型T

  a.和函数模板不同,类模板只能显示指定具体类型,无法自动推导;定义对象时要加<type>指定具体类型,如下所示。

Operator<int> op1;Operator<string> op1;int i = op1.op(1, 2);string s = op2.op("Hello", "World!");

  b.声明的泛指类型T可以出现在类模板的任意地方;
  
  c.类模板必须定义在.h文件中;
  
  d.且不能分开实现在不同的文件中。;
  
  e.类模板外部定义的成员函数需要加上模板<>声明。
  

3.类模板的应用场景

  类模板主要用于存储和组织数据元素的类;类中数据组织的方式和数据元素的具体类型无关;比如:数组类、链表类、Stack类、Queue类等。
   
  C++中将模板的思想应用于类,使得类的实现不关注数据元素的具体类型,而只关注类所需要实现的功能。

4.编译器如何编译函数模板

  编译器对类模板的处理方式和函数模板相同。
  
  a.编译器根据类模板的具体类型产生不同的类
  
  b.编译器会对函数模板进行两次编译,首先在声明的地方对类模板代码本身进行编译,然后在使用的地方对参数替换后的代码进行编译。

5.类模板的使用

下面给出类模板的初步使用:

Operator.h

#ifndef _OPERATOR_H_#define _OPERATOR_H_template < typename T >class Operator{public:    T add(T a, T b);    T minus(T a, T b);    T multiply(T a, T b);    T divide(T a, T b);};template < typename T >T Operator<T>::add(T a, T b){    return a + b;}template < typename T >T Operator<T>::minus(T a, T b){    return a - b;}template < typename T >T Operator<T>::multiply(T a, T b){    return a * b;}template < typename T >T Operator<T>::divide(T a, T b){    return a / b;}#endif

main.cpp

#include <iostream>#include <string>#include "Operator.h"using namespace std;int main(){    Operator<int> op1;    cout << "op1.add(1, 2) = " << op1.add(1, 2) << endl;    cout << "op1.multiply(4, 5) = " << op1.multiply(4, 5) << endl;    cout << "op1.minus(5, 6) = " << op1.minus(5, 6) << endl;    cout << "op1.divide(10, 5) = " << op1.divide(10, 5) << endl;    return 0;}

运行结果如下所示:

这里写图片描述

6.多参数类模板

   类模板可以定义任意多个不同的类型参数, 如下所示:

template <typename T1, typename T2>class Test {public:    void add(T1, a, T2 b);};Test<int, float> t;     // 定义对象

7.类模板特化

  类模板可以被特化:
  a.指定类模板的特定实现
  
  b.部分类型参数必须显示指定,比如返回值类型必须显示指定;
  
  c.根据类型参数分开实现类模板
  
  d.类模板的特化可以分为:
   部分特化:用特定规则约束类型参数;    
   完全特化:完全显示指定类型参数。

  e.模板特化注意事项:
   特化只是模板的分开实现 ,本质上是同一个类模板;
   特化模板的使用方式是统一的,必须显示指定每一个类型参数。
   
下面给出模板特化的示例:

#include <iostream>#include <string>using namespace std;template < typename T1, typename T2 >class Test{public:    void add(T1 a, T2 b)    {        cout << "void add(T1 a, T2 b) = " << a + b << endl;        //cout << a + b << endl;    }};template < typename T1, typename T2 >class Test < T1*, T2* >      // 关于指针的特化实现{public:    void add(T1* a, T2* b)    {        cout << "void add(T1* a, T2* b) = " << *a + *b << endl;        //cout << *a + *b << endl;    }};template < typename T >class Test < T, T >    // 当 Test 类模板的两个类型参数完全相同时,使用这个实现{public:    void add(T a, T b)    {        cout << "void add(T a, T b) = " << a + b << endl;        //cout << a + b << endl;    }    void print()    {        cout << "class Test < T, T >" << endl;    }};template <  >class Test < void*, void* >    // 当 T1 == void* 并且 T2 == void* 时{public:    void add(void* a, void* b)    {        cout << "void add(void* a, void* b)" << endl;        cout << "Error to add void* param..." << endl;    }};int main(){      Test<int, float> t1;    Test<long, long> t2;    Test<void*, void*> t3;    t1.add(1, 2.5);    t2.add(5, 5);    t2.print();    t3.add(NULL, NULL);    Test<int*, double*> t4;    int a = 1;    double b = 0.1;    t4.add(&a, &b);    return 0;}

运行结果如下图所示:

这里写图片描述

8.数值型参数

  模板参数可以是数值参数(非类型参数),格式如下:

template <int N>class{public:    static const int value = N; };

  模板参数是在编译阶段被处理的单元,因此模板参数必须在编译阶段必须准确无误的唯一确定,下面列出数值型模板参数的限制:
  
  1.变量不能作为模板参数;
  2.浮点数不能作为模板参数;
  3.类对象不能作为模板参数。
  总之,一切在编译阶段无法确定的参数均不能作为模板参数。

  下面是一道面试题:

用你觉得最高效的方法求1+2+3+...+N的值!

  下面通过模板数值型参数给出解答:

#include <iostream>using namespace std;template <int N>class Sum{public:    static const int value = Sum<N-1>::value + N;};template < >class Sum <1>{public:    static const int value = 1;};int main(){    cout << "1+2+3+...+10 = " << Sum<10>::value << endl;    cout << "1+2+3+...+100 = " << Sum<100>::value << endl;      return 0;}

  Sum::value的值在编译的时候就已经确定了,因此用此方法应该是最高效的了,下面为运行结果:

这里写图片描述

原创粉丝点击