C++基础:模板


模板(Template)指C++程序设计设计语言中采用类型作为参数的程序设计,支持通用程序设计。C++ 的标准库提供许多有用的函数大多结合了模板的观念,如STL以及IO Stream。模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。

模板是一种对类型进行参数化的工具,通常有两种形式:函数模板类模板

  • 函数模板:针对仅参数类型不同的函数;
  • 类模板:针对仅数据成员和成员函数类型不同的类。

使用模板的目的就是能够让程序员编写与类型无关的代码。

C++只有模板显式实例化(explicit instantiation),隐式实例化(implicit instantiation),特化(specialization,也译作具体化,偏特化)。

类模板定义

  • 定义:
template<typename 形参名,typename 形参名,…>
class 类名{ ... };
  • 示例如下:
template <class T>
class Arrary
{
private:
  T* ar;
  int l;
...
};//template class declaration.
  • 类外定义成员函数:
函数返回类型 类名<模板形参名>::函数名(参数列表){函数体}

注意:

  • 类模板不能重载,可以全特化、偏特化。
  • 对主版本模板类、全特化类、偏特化类的调用优先级从高到低进行排序是:
    全特化类 > 偏特化类 > 主版本模板类
    
  • 由于编译器只能通过include <看到> 头文件而找不到模板实现代码。为避免产生链接问题,模板类的声明和定义必须放在一起(头文件中)

函数模板定义

在这里插入图片描述

  • 定义:
template <class 形参名,class 形参名,......> 
返回类型 函数名(参数列表)
{
	函数体
}

其中template和class是关键字,class可以用typename 关键字代替,在这里typename 和class没区别,<>括号中的参数叫模板形参,模板形参和函数形参很相像,模板形参不能为空。

  • 示例如下:
template<class T>
void swap(T &a, T &b )
{
  T temp;
  temp = a;
  a = b;
  b = temp;
};

注意:

  • 函数模板是可以被重载的(类模板不能被重载),也就是说允许存在两个同名的函数模板,还可以对它们进行实例化,使它们具有相同的参数类型。
  • 函数模板只能全特化,不可以偏特化。

函数模板重载

// 主模板函数
template<typename T, class N> void func(T num1, N num2)
{
    //cout << "num1:" << num1 << ", num2:" << num2 <<endl;
}
 
// 重载模板函数
template<class N> void func(int num1, N num2)
{
    cout << "num1:" << num1 << ", num2:" << num2 <<endl;
}

// 重载模板函数
template<class N> void func(N num1)
{
    cout << "num1:" << num1 <<endl;
}

隐式实例化 implicit instantiation

模板只有在运行时才会生成相应的实例,会影响执行效率。
编译器进行类型推导,在编译期间生成相应的实例

swap<int>(a,b);  

其中<int>是可省的

Array<int> arr;

其中<int>是不可省的

显式实例化 explicit instantiation

显式实例化,需要在模板定义后显式声明,在编译期间生成相应的实例。 虽然会增加编译时间,但提高了执行效率。

注意显式实例化的写法:

template void swap<int>(int &a,int &b);  
template class Array<int>;   //explicit instantiation. 显式实例化

模板特化/具体化 specialization

对于函数模板,只有全特化,不能偏特化。偏特化功能可以通过模板函数的重载实现。
对于类模板,可以全特化、偏特化,但不能重载。(没有重载类的说法)

C++模板全特化之后已经失去了Template的特性。

一个模板被全特化/偏特化的条件:

  1. 必须有一个主模板类
  2. 模板类型被全部/部分明确化

函数模板的全特化

// 主模板
template<typename T, class N> 
void func(T num1, N num2)
{
    //cout << "num1:" << num1 << ", num2:" << num2 <<endl;
}

// 全特化模板
template<> 
void func(int num1, double num2)
{
    cout << "num1:" << num1 << ", num2:" << num2 <<endl;
}

类模板的全特化

注意全特化类的定义写法

// 主模板
template<typename T, class N> 
class Test_Class
{
public:
    static bool comp(T num1, N num2)
    {
        return (num1<num2)?true:false;
    }
};
 
// 全特化模板
template<> 
class Test_Class<int, double>
{
public:
    static bool comp(int num1, double num2)
    {
        return (num1<num2)?true:false;
    }
};

类模板的偏特化

注意偏特化类的定义写法

// 主模板
template<typename T, class N> 
class Test_Class
{
public:
    static bool comp(T num1, N num2)
    {
        return (num1<num2)?true:false;
    }
};
 
// 偏特化模板
template<class N> 
class Test_Class<int, N>
{
public:
    static bool comp(int num1, double num2)
    {
        return (num1<num2)?true:false;
    }
};

特化和重载的区别

不能将特化和重载混为一谈。全特化和偏特化都没有引入一个全新的模板或者模板实例。它们只是对原来的泛型(或者非特化)模板中已经隐式声明的实例提供另一种定义。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值