26、C++类模板

C++类模板

目的:当同一种逻辑操作需要面对不同的数据类型时,如果不使用模板,就需要定义针对

不同数据类型的类,这样容易造成代码冗余和管理复杂。当采用了类模板时,就可以

定义一个逻辑模板,用相同的程序处理不同的数据类型,当需要处理指定数据类型时,

只要用该类型声明一个类模板实例。就使用进行相应的操作。

注:类模板的定义与实现要放在同一个文件中


一、类模板

普通类模板定义:

基本语法:

template<typename T1,typename T2...,非类型参数列表>

class 类模板名

{

类模板体

};

1、T1 T2的实参是数据类型名称,可以是系统预定义的。也可以是用户自定义的

2、非类型参数如:int size,这个size就是非类型参数,实参必须是常量表达式

,必须是编译期就能确定的值。

3、模板参数可有默认实参,如:

template <typename T=int , int  size=100>

class Array

. . .

};

实例化: Array < > arryint; // 不可省略  < >

注:如果在定义类模板实体时,需要该类模板的一个实例作为参数之类的,并且该

实例的参数就是本模板的参数,就是本模板的参数,则可以直接使用类模板名

二、类模板成员函数

定义类模板的成员函数时,可以直接在类模板的内部定义,也可在类模板的外部定义,

注:类模板外部定义时,比一般的类的定义多了一个”template <模板参数>” 说明,

还有类名后加了一个 “<模板参数>”

基本语法:

template<模板参数列表>

返回类型 类模板名<模板参数列表>::函数名(函数参数列表)

函数体

1、类模板名后面的 “模板参数列表” 可以省略类型参数的typename

等关键字,以及非类型参数的类型关键字。

三、实例化类模板

类模板的实例化就是根据数据类型,实际的生成一个类对象。

与函数模板实例化不同的是,类模板在实例化时,没有参数推导机制,也就是没有

编译器不能根据给出的数据,自行推导实参数据类型,只能由开发者指定实参。

基本语法:

类模板名<模板实参列表> 实例名;

类模板实例化后,生成的实例类对象名,就是一个实际存在的类对象。

可以当作一般的类对象来使用。

类模板只在需要的时候才实例化,如程序中使用类模板的某个指针或

者引用,而没有通过这个指针或引用访问对象的数据成员或数据成员,则该类

模板不会被实例化。

如:

void Print(Stack<int> &vi)

Stack<int> *pvi=&vi;  //并不会实例化

void Print(Stack<int> &vi)

Stack<int> *pvi=&vi;

cout<<pvi->Pop()<<endl;//模板会被实例化。

四、类模板的静态成员

和普通类一样,模板也可以有自己的静态成员,在类内声明,类外定义,

所不同的是,每种类型的类模板的实例都有自己的一组静态成员。静态

成员在类外定义(初始化)

基本语法:

template <模板参数列表>

类型名 类模板名<模板参数列表>::静态成员变量=初始值;

注:类模板名后的模板参数列表,可以省略关键字。

五、类模板的友元

相当于普通类的友元一样,可以通过类模板的对象(引用或者指针)访问类模板的私

有成员和保护成员。

在类模板中可以出现三种友元声明:
(1)普通非模板类或函数的友元声明,将友元关系授予明确指定的类或函数。
(2)类模板或函数模板的友元声明,授予对友元所有实例的访问权。
(3)只授予对类模板或函数模板的特定实例的访问权的友元声明。

六、类模板的特化

有的时候某些类型不能直接用来实例化类模板,或者说直接实例化不能满足需要,

此时就要针对这种类型进行特化,包括特化(即全特化)和偏特化。

1、全特化

目的:为了针对特殊的类型进行特殊处理,重新修改成新的逻辑,定义一个

新的特化的类模板。

特点:template后没有形参说明,类模板名加了模板实参列表。

基本语法:

template<>

class  类模板名<模板实参列表>

新的逻辑操作

};

2、偏特化(部分特化)

特点:template后的模板形参的形参没有全部不写,类模板名后添加了参数说明。

或者两个都

基本语法:

template<模板形参列表>

class 类模板名<模板形参表>

};

注:类模板名后的形参,可以把template后的形参当作已知的类型,组合成新

的类型来作为类模板的参数。然后通过实例化template的形参,

最后进一步确定类模板的实参。

注:所有特化类模板之前,一定先需要定义同名的非特化类模板,否则会有编译错误

七、类模板的匹配规则

类模板的匹配遵循使用“特化程度最高”原则,模板参数最准确匹配的拥有最

高的实例化优先权。

八、三种类型的特化     

1、全特化

2、特化为引用和指针

3、特化为另外一个模板类

测试程序:

#include <iostream>

using namespace std;

//类模板的基本实现

//使用类模板实现对不同数据的栈存储管理

template <typename T,int size>

class Stack

{

public:

    Stack():top(0),count(0)

    {

    }

    int Push(T data)//入栈操作

    {

        if(top<size)//栈没有满 top-size时,表示存满

        {

            stack_data[top]=data;

            top++;

            return 0;//返回0代表入栈成功

        }

        return 1;

    }

    int Pop();//出栈操作

    T  getTopValue()//获取栈顶元素

    {

        if(top>0)

        {

            return stack_data[--top];

        }

        return T(1);

    }

    int getTop()

    {

        return this->top;//返回栈顶指针

    }

    void PrintStack();

private:

  T stack_data[size];

  int top;//始终指向栈顶元素的上一个位置

  int count;

};

template <typename T,int size>

int Stack<T,size>::Pop()

 {

        if(top>0)

        {

            top--;

            return 0;

        }

        return 1;

}

template <typename T,int size>

void Stack<T,size>::PrintStack()

{

    for(int temp=top;temp>0;temp--)

    {

        cout<<stack_data[temp-1]<<"->";

    }

    cout<<endl;

}

int main()

{

    Stack<int,10> int_stack;//使用类模板实例化一个类对象

//    cout<<int_stack.getTop()<<endl;

//    cout<<(int)int_stack.getTopValue()<<endl;

    cout<<"Int型数据:"<<endl;

    for(int i=0;i<11;i++)

    {

      if(int_stack.Push(i+1)==1)//入栈操作

      {

          cout<<"栈已满"<<"元素:"<<i+1<<"入栈失败"<<endl;

      }

    }

    int_stack.PrintStack();

    int_stack.Pop();

    int_stack.Push(11);

    int_stack.PrintStack();

    cout<<"栈顶元素:"<<int_stack.getTopValue()<<endl;

    cout<<"Double型数据:"<<endl;

    Stack<double,20> double_stack;

    for(double i=0;i<22.0;i++)

    {

      if(double_stack.Push(i+2.0)==1)//入栈操作

      {

          cout<<"栈已满"<<"元素:"<<i+2.0<<"入栈失败"<<endl;

      }

    }

    double_stack.PrintStack();

    double_stack.Pop();

    double_stack.Push(22.0);

    double_stack.PrintStack();

    cout<<"栈顶元素:"<<double_stack.getTopValue()<<endl;

    return 0;

}


输出结果:

Int型数据:

栈已满元素:11入栈失败

10->9->8->7->6->5->4->3->2->1->

11->9->8->7->6->5->4->3->2->1->

栈顶元素:11

Double型数据:

栈已满元素:22入栈失败

栈已满元素:23入栈失败

21->20->19->18->17->16->15->14->13->12->11->10->9->8->7->6->5->4->3->2->

22->20->19->18->17->16->15->14->13->12->11->10->9->8->7->6->5->4->3->2->

栈顶元素:22

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值