26.C++- 泛型编程之类模板(详解)

在上章25.C++- 泛型编程之函数模板(详解) 学习了后,本章继续来学习类模板

 

类模板介绍

和函数模板一样,将泛型思想应用于类.

编译器对类模板处理方式和函数模板相同,都是进行2次编译

类模板通常应用于数据结构方面,使得类的实现不在关注数据元素的具体类型,而只关注需要实现的功能

比如: 数组类,链表类,Queue类,Stack类等

使用方法

  • 通过template关键字来声明,然后通过typename关键字来定义模板类型,如下图所示:

类模板的使用

  • 定义对象时,必须指定类模板类型,因为编译器无法推导类型
  • 使用具体类型<Type>来定义对象

如下图所示:

初探类模板

写一个类模板,实现不同类型的加减乘除

#include <iostream>
#include <string>

using namespace std;

template < typename T >
class Operator
{
public:
     T add(T a, T b)
    {
        return a + b;
    }

     T minus(T a, T b)
    {
        return a - b;
    }

     T multiply(T a, T b)
    {
        return a * b;
    }

     T divide(T a, T b)
    {
        return a / b;
    }
};
string operator-(string& l, string& r)   //由于string类没有重载减号操作符,所以我们自定义一个
{
    return "Minus";
}

int main()
{
    Operator<int>  op1;            //定义对象时,需要指定类模板类型
    cout << op1.add(1, 2) << endl;          

    Operator<string>  op2;         //定义对象时,需要指定类模板类型
    cout << op2.add("D.T.", "Software") << endl;
    cout << op2.minus("D.T", "Software") << endl;
    return 0;
}

运行打印:

3
D.T. Software
Minus

类模板的工程应用

  • 类模板必须在.h头文件中定义
  • 类模板的成员函数不能分开在不同的文件中实现
  • 类模板外部定义的成员函数,和模板函数一样,还需要加上模板template <typename T>声明

接下来,我们便修改上面代码定义的Operator类模板,只需要写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

多参数类模板

类模板可以定义任意多个不同的类型参数,同时还要必须指定每个模板参数

例如:

template < typename T1,typename T2 >
class Operator
{
public:
    void add(T1 a, T2 b);
};

template < typename T1,typename T2 >
void Operator<T1,T2 > :: add(T1 a, T2 b)
{
        cout<<a+b<<endl;
}

int main()
{
    Operator<int,float> op1;                 //定义op1对象时,必须指定类模板类型
    op1.add(2,2.1);                                  //4.1
    return 0;
}

运行打印:

4.1

从结果来看,上面的类模板好像已经实现了add加法运算.但是却不能支持指针类型.

其实,类模板也可以像函数重载一样, 类模板通过特化的方式可以实现特殊情况.

类模板特化

  • 表示可以存在多个相同的类名,但是模板类型都不一致(和函数重载的参数类似)
  • 特化类型有完全特化部分特化两种类型
  • 完全特化表示显示指定类型参数,模板声明只需写成template<>,并在类名右侧指定参数,比如:
template < typename T1,typename T2 >  //声明的模板参数个数为2个
class Operator                        //正常的类模板
{
public:
        void add(T1 a, T2 b)
       {
              cout<<a+b<<endl;
       }
};

template <>                           //不需要指定模板类型,因为是完全特化的类模板
class Operator< int , int>           //指定类型参数,必须为2个参数,和正常类模板参数个数一致

{                                               

public:

void add(int a, int b)

{

cout<<a+b<<endl;

}

};

int main()

{

       Operator<int,int> Op1;        //匹配完全特化类模板:class Operator< int,int>

       Operator<int,float> Op2;     //匹配正常的类模板

       return 0;

}
  • 部分特化表示通过特定规则约束类型参数,模板声明和类似,并在类名右侧指定参数,比如:
template < typename T1,typename T2 >           //声明的模板参数个数为2个
class Operator                                 //正常的类模板
{
public:
        void add(T1 a, T2 b)
       {
              cout<<a+b<<endl;
       }
};

template < typename T >          //有指定模板类型以及指定参数,所以是部分特化的类模板
class Operator< T* ,T*>          //指定类型参数,必须为2个参数,和正常类模板参数个数一致
{
public:
  void add(T* a, T* b)
  {
              cout<<*a+*b<<endl;
  }
};

int main()
{
     Operator<int*,int*> Op1;            //匹配部分特化: class Operator< T* ,T*>
     Operator<int,float> Op2;           //匹配正常的类模板: class Operator
return 0;
}
  • 编译时,会根据对象定义的类模板类型,首先去匹配完全特化,再来匹配部分特化,最后匹配正常的类模板.

初探类模板特化

#include <iostream>

using namespace std; 

template < typename T1,typename T2 >
class Operator                                            //正常的类模板
{
public:
        void add(T1 a, T2 b)
       {
              cout<<"add(T1 a, T2 b)"<<endl;
              cout<<a+b<<endl;
       }
};

template < typename T >
class Operator<T,T>                                //部分特化的类模板,当两个参数都一样,调用这个
{
public:
         void add(T a, T b)
       {
              cout<<"add(T a, T b)"<<endl;
              cout<<a+b<<endl;
       }
};

template < typename T1,typename T2 >
class Operator<T1*,T2*>                                   //部分特化的类模板,当两个参数都是指针,调用这个
{
public:
        void add(T1* a, T2* b)
       {
              cout<<"add(T1* a, T2* b)"<<endl;
              cout<<*a+*b<<endl;
       }
};

template < >
class Operator<void*,void*>                             //完全特化的类模板,当两个参数都是void*,调用这个
{
public:
        void add(void* a, void* b)
       {
              cout<<"add(void* a, void* b)"<<endl;
              cout<<"add void* Error"<<endl;                 //void*无法进行加法
       }
};

int main()
{
       int *p1 = new int(1);
       float *p2 = new float(1.25);

       Operator<int,float>  Op1;        //匹配正常的类模板:class Operator
       Op1.add(1,1.5);

       Operator<int,int>  Op2;          //匹配部分特化的类模板:class Operator<T,T>
       Op2.add(1,4);

       Operator<int*,float*>  Op3;      //匹配部分特化的类模板:class Operator<T1*,T2*>
       Op3.add(p1,p2);

       Operator<void*,void*>  Op4;      //匹配完全特化的类模板:class Operator<void*,void*>
       Op4.add(NULL,NULL);  

       delete p1;
       delete p2;

       return 0;
}

运行打印:

add(T1 a, T2 b)
2.5

add(T a, T b)
5

add(T1* a, T2* b)
2.25

add(void* a, void* b)
add void* Error

数值型模板参数

之前,我们学习的模板参数都是带泛型的(表示不同类型),其实模板参数也可以是数值型参数,如下图所示:

  • 数值型模板参数必须在编译时被唯一确定

比如: 变量在运行期间是可变的,所以不能作为模板参数.以及浮点数(不精确),类对象(可变)等等.

接下来,我们便通过数值参数的类模板来求 1+2+3+...+N的值

代码如下所示:

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;
}

运行打印:

1 + 2 + 3 + ... + 10 = 55
1 + 2 + 3 + ... + 100 = 5050

 

原文地址:https://www.cnblogs.com/lifexy/p/8781525.html

时间: 2024-09-29 19:52:03

26.C++- 泛型编程之类模板(详解)的相关文章

25.C++- 泛型编程之函数模板(详解)

1)初探函数模板 2)深入理解函数模板 3)多参函数模板 4)重载函数模板 当我们想写个Swap()交换函数时,通常这样写: 但是这个函数仅仅只能支持int类型,如果我们想实现交换double,float,string等等时,就还需要从新去构造Swap()重载函数,这样不但重复劳动,容易出错,而且还带来很大的维护和调试工作量.更糟的是,还会增加可执行文件的大小. 函数模板 一种特殊的函数,可通过不同类型进行调用 函数模板是C++中重要的代码复用方式 通过template关键字来声明使用模板 通过

Django框架模板详解

Django模板详解 模板使用 模板基本由两个部分组成,一是HTML代码,二是逻辑控制代码. 逻辑控制的实现又基本由三个部分组成: 1. 变量的使用 {{ person_name }} #使用双大括号来引用变量 2. tag的使用 {% if ordered_warranty %} #使用大括号和百分号的组成来表示使用Django提供的 template tag {% for item in item_list %} <li>{{ item }}</li> {% endfor %}

常见26个jquery使用技巧详解(比如禁止右键点击、隐藏文本框文字等)

来自:http://www.xueit.com/js/show-6015-1.aspx 本文列出jquery一些应用小技巧,比如有禁止右键点击.隐藏搜索文本框文字.在新窗口中打开链接.检测浏览器.预加载图片.页面样式切换.所有列等高.动态控制页面字体大小.获得鼠标指针的X值Y值.验证元素是否为空.替换元素.延迟加载.验证元素是否存在于Jquery集合中.使DIV可点击.克隆对象.使元素居中.计算元素个数.使用Google主机上的Jquery类库.禁用Jquery效果.解决Jquery类库与其他J

Square Coins (HDU 1398) ———母函数模板详解

Square Coins Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 7748    Accepted Submission(s): 5238 Problem Description People in Silverland use square coins. Not only they have square shapes but

c3p0-config.xml模板详解

c3p0-config.xml模板详解 <c3p0-config> <default-config> <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数.Default: 3 --> <property name="acquireIncrement">3</property> <!--定义在从数据库获取新连接失败后重复尝试的次数.Default: 30 --> <property name=&qu

【转】 C++模板详解

C++模板 模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数.返回值取得任意类型. 模板是一种对类型进行参数化的工具: 通常有两种形式:函数模板和类模板: 函数模板针对仅参数类型不同的函数: 类模板针对仅数据成员和成员函数类型不同的类. 使用模板的目的就是能够让程序员编写与类型无关的代码.比如编写了一个交换两个整型int 类型的swap函数,这个函数就只能实现int 型,对double,字符这些类型无法实现,要实现这些类型

C++ 模板详解(一)(转)

C++模板 模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数.返回值取得任意类型. 模板是一种对类型进行参数化的工具: 通常有两种形式:函数模板和类模板: 函数模板针对仅参数类型不同的函数: 类模板针对仅数据成员和成员函数类型不同的类. 使用模板的目的就是能够让程序员编写与类型无关的代码.比如编写了一个交换两个整型int 类型的swap函数,这个函数就只能实现int 型,对double,字符这些类型无法实现,要实现这些类型

C++ 模板详解(二)(转)

四.类模板的默认模板类型形参 1.可以为类模板的类型形参提供默认值,但不能为函数模板的类型形参提供默认值.函数模板和类模板都可以为模板的非类型形参提供默认值. 2.类模板的类型形参默认值形式为:template<class T1, class T2=int> class A{};为第二个模板类型形参T2提供int型的默认值. 3.类模板类型形参默认值和函数的默认参数一样,如果有多个类型形参则从第一个形参设定了默认值之后的所有模板形参都要设定默认值,比如template<class T1=

C++模板详解

C++模板 模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数.返回值取得任意类型. 模板是一种对类型进行参数化的工具: 通常有两种形式:函数模板和类模板: 函数模板针对仅参数类型不同的函数: 类模板针对仅数据成员和成员函数类型不同的类. 使用模板的目的就是能够让程序员编写与类型无关的代码.比如编写了一个交换两个整型int 类型的swap函数,这个函数就只能实现int 型,对double,字符这些类型无法实现,要实现这些类型