C++程序设计——十

C++模板详解

还记得前面我们学习重载(overloading),为了应付不同情况下调用某一函数的情况,为了提高函数的鲁棒性,我们就可以重载该函数,让他能够自动适应不同的环境。
现在我们换个思路想一下,一般来说,重载函数的功能都是相同的,只不过为了应对不同的输入,而设置了重载函数。但我们自己写的时候很难考虑到所有的情况,有时还是会因重载函数定义不全面而带来调用错误。
那么,我们能不能只写一套代码来解决这个问题呢?
可以的,就是通过模板(template)
我们通过模板可以进行泛型编程——即以一种独立于任何特定类型的方式编写代码,不指定特定的类,那么理论上任何类型都可以运行。

模板定义

模板就是实现代码重用机制的一种工具,它可以实现类型参数化,即把类型定义为参数, 从而实现了真正的代码可重用性。
模版可以分为两类,一个是函数模版,另外一个是类模版。

函数模板

template <typename type>
ret-type func-name(parameter list)
{
   // 函数的主体
}

实际上,在函数模板中,模板的用处主要在将参数的类型泛化,它能够自动适应各个类型,在下面的代码中,字符T就代表所有可能的类型

#include <iostream>
#include <string>
 
using namespace std;
 
template <typename T>
T const& Max (T const& a, T const& b) 
{ 
    if(a>b)
    {
        cout<<a<<">"<<b<<endl;
    }
    else if(a==b)
    {
        cout<<a<<"等于"<<b<<endl;
    }
    else
    {
        cout<<a<<"<"<<b<<endl;
    }
    return a < b ? b:a;
} 
int main ()
{
    cout<<"整型比大小,请输入两个整数:"<<endl;
    int i,j;
    cin>>i;
    cin>>j;
    cout << "整型比大小结果:" << Max(i, j) << endl; 

    cout<<"double类型比大小,请输入两个浮点数:"<<endl;;
 
    double f1,f2;
    cin>>f1;
    cin>>f2;
    cout << "double类型比大小" << Max(f1, f2) << endl; 
 
    char c1='A';
    char c2='K';
    cout<<"char类型比大小:"<<Max(c1,c2)<<endl;

    // cout<<"整型和浮点数比大小:"<<endl;
    // cout<<"请输入一个整数:";
    // cin>>i;
    // cout<<"请输入一个浮点数"<<endl;
    // cin>>f1;
    // cout<<"整型和浮点数比大小结果:"<<Max(i,f1);
    //错误!调用函数模板时,因为参数都是T类型的,虽然没有指明类型,但必须保证类型一致
 
   return 0;
}

运行结果如下:

整型比大小,请输入两个整数:
56
32
整型比大小结果:56>32
56
double类型比大小,请输入两个浮点数:
65.5
235.5
double类型比大小65.5<235.5
235.5
char类型比大小:A<K
K

在上述程序最后,展示了Max()函数对整型和double类型的比大小,显示错误。这是因为Max()函数输入的形参都是T类型的,这说明两者必须是同一种类型,不能进行不同类型的比大小。

类模板

正如定义函数模板一样,我们也可以定义类模板
一般形式如下:

template <class type>
class class-name 
{
}

里面的type是占位符类型名称,可以在类被实例化的时候进行指定。
在生活中,一个人的信息最起码有两个:身份证号,姓名;身份证号可以为int类型,但有时也可以为string类型。
下面的代码就实例化了一个满足身份证号既可以为int型也可以是string型的类:T1代表ID可能的类型,T2代表Name可能的类型。

#include <iostream>
#include <string>
using namespace std;
template <class T1,class T2>
class Person
{
public:
    T1 ID;  //身份证号
    T2 Name;  //其他信息
    Person(T1 id,T2 name):ID(id),Name(name){};
    void lol()
    {
        cout<<"id:"<<ID<<endl;
        cout<<"name:"<<Name<<endl;
    }
};

int main()
{
    Person<int,string> ming(117,"Bruce");
    ming.lol();
	
	Person<string,string> hei("11x","Jackie");
    hei.lol();
    return 0;
}

输出如下

id:117
name:Bruce
id:11x
name:Jackie

我们可以看到,实例化一个类模板时,真实类型参数表中的参数是具体的类型名,如 string、int 或其他类的名字,它们用来一一对应地替换类模板定义中“类型参数表”中的类型参数。
在main函数中,其实自动生成了两个不同的类,ming对象的类型为Person<int,string>,hei对象的类型为Person<string,string>
这个编译器由类模板生成类的过程叫类模板的实例化,由类模板实例化得到的类叫模板类。

函数模板作为类模板的成员

类模板的成员函数当然也可以是一个前面提到的函数模板,函数模板只有在被调用时才会被实例化,如下:

#include <iostream>
#include <string>
using namespace std;
template <class T1,class T2>
class Person
{
public:
    T1 ID;  //身份证号
    T2 Name;  //其他信息
    Person(T1 id,T2 name):ID(id),Name(name){};
    void lol()
    {
        cout<<"id:"<<ID<<endl;
        cout<<"name:"<<Name<<endl;
    }
    T1 max(T1 a,T1 b)
    {
        if(a>b)
        {
            cout<<a<<">"<<b<<endl;
        }
        else if(a==b)
        {
            cout<<a<<"等于"<<b<<endl;
        }
        else
        {
            cout<<a<<"<"<<b<<endl;
        }
        return a < b ? b:a;
    }
};

int main()
{
    Person<int,string> ming(117,"Bruce");
    ming.lol();

    Person<string,string> hei("11x","Jackie");
    hei.lol();

    ming.max(123,456);
    ming.max(56.2,65.3);
    return 0;
}

输出如下

id:117
name:Bruce
id:11x
name:Jackie
123<456
56<65

在修改后的代码中,倒数第二行我们有:ming.max(56.2,65.3);
但输出仍为整型:56<65,这是因为我们前面提到过,ming对象的类型为Person<int,string>,所以它会将两个浮点数进行强制类型转换,变为整型,再进行函数的执行

类模板与继承

类模板相关的继承有四种:

  • 普通类继承类模板
  • 类模板继承普通类
  • 类模板继承类模板
  • 类模板继承由继承模板参数指定的基类
    1、普通类继承类模板
template<class T>
class one
{
    T data;
};
class sub:public one<int>
{
};

2、类模板继承普通类

class one
{
};
template<class T>
class sub:public one
{
	T data;
};

3、类模板继承类模板

template<class T>
class one
{
	T data1;
};
template<class T1,class T2>
class sub:public one<T1>
{
	T2 data2;
};

4、模板类继承模板参数给出的基类——继承哪个基类由模板参数决定

#include<iostream>
using namespace std;

class BaseA{
public:
    BaseA(){cout<<"BaseA founed"<<endl;}
};

class BaseB{
public:
    BaseB(){cout<<"BaseB founed"<<endl;}
};

template<typename T, int rows>
class BaseC{
private:
    T data;
public:
    BaseC():data(rows){
        cout<<"BaseC founed "<< data << endl;}
};

template<class T>
class Derived:public T{
public:
    Derived():T(){cout<<"Derived founed"<<endl;}
};


void main()
{
    Derived<Base A> x;// BaseA作为基类
    Derived<Base B> y;// BaseB作为基类
    Derived<Base C<int, 3> > z; // BaseC<int,3>作为基类
}

总结

模板在C++中是非常重要的,它是实现代码重用机制的一种工具;通过模板,我们可以进行泛型编程,它可以实现类型参数化,从而实现了真正的代码可重用性。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值