C++基础:模板,函数模板和类模板

本文详细介绍了C++中的模板使用,包括函数模板用于实现泛型函数,如求最大值、交换对象、类型转换等;类模板用于创建泛型类,如圆形类和顺序列表类;还探讨了模板特化,解决特定类型比较问题,以及类模板的全特化和偏特化。最后,展示了非类型模板参数的应用,用于处理数组参数。
摘要由CSDN通过智能技术生成

模板是允许函数或类通过泛性的形式表现或运行的特性

1. 函数模板

模板可以使函数或者类只写一份代码而对应不同的类型

取整数、小数、字符中的最大值

#include <iostream>
using namespace std;

/*
int Max(int a,int b){
        return a>b?a:b;
}

double Max(double a,double b){
        return a>b?a:b;
}

double Max(char a,char b){
        return a>b?a:b;
}
*/

template<typename T>         // 起一个模板类型名
T Max(T a,T b){
        return a>b?a:b;
}

int main(){
        cout << Max(10,12) << endl;        // int Max(int a,int b)
        cout << Max(1.0,1.2) << endl;        // double Max(double a,double b)
        cout << Max('a','c') << endl;        // char Max(char a,char b)
}

结果为:

12
1.2
c

两个对象交换顺序

#include <iostream>
#include <sstream>
using namespace std;
/*
void Swap(int& a,int& b){
        int t = a;
        a = b;
        b = t;
}
*/

// 两个对象交换
template <typename T>
void Swap(T& a,T& b){
        T t = a;
        a = b;
        b = t;
}

int main(){
        {
        int a = 10;
        int b = 20;
        cout << a << "," << b << endl;
        Swap(a,b);                         // void Swap(int,int)
        cout << a << "," << b << endl;
        }
        {
        float a = 12.3;
        float b = 32.1;
        cout << a << "," << b << endl;
        Swap(a,b);                         // void Swap(double,double)
        cout << a << "," << b << endl;
        }
}

结果为:

10,20
20,10
12.3,32.1
32.1,12.3

把某个类型转化为字符串

#include <iostream>
#include <sstream>
using namespace std;

//把某个类型转换为字符串
template <typename T>
string NumberToString(T n){
        ostringstream oss;
        oss << n;
        return oss.str();
}

int main(){
        cout << NumberToString(10) << endl;
        cout << NumberToString(1.3) << endl;
}

结果为:

10
1.3

对于不知道返回值类型的情况,我们需要用<尖括弧>设定类型
字符串转换为某个类型

#include <iostream>
#include <sstream>
using namespace std;

// 字符串转换为某个类型
template <typename T>
T StringToNumber(const string& s){
        T res;
        istringstream iss(s);
        iss >> res;
        return res;
}

int main(){
        cout << StringToNumber<int>("20") << endl;
        cout << StringToNumber<float>("1.25") << endl;
}

结果为:

20
1.25

对于传入两个数类型不一致,也可以做相应设定

#include <iostream>
using namespace std;

template<typename T>
T Max(T a,T b){
        return a>b?a:b;
}

int main(){
        cout << Max((double)10,12.2) << endl;     // 两个数类型不匹配   
        cout << Max<double>(10,12.2) << endl;
}

结果为:

12.2
12.2

该程序不能使用小写max,会出现函数名冲突的情况
要想使用小写max,需要添加命名空间

#include <iostream>
using namespace std;

namespace My{              // 添加命名空间
	    template<typename T>
	    T max(T a,T b){
 		      return a>b?a:b;
	    }
}

int main(){
        cout << My::max((double)10,12.2) << endl;
        cout << My::max<double>(10,12.2) << endl;
}

2. 类模板

与函数模板不同,类模板必须定义参数类型
求圆的周长和面积

#include <iostream>
#include <cmath>
using namespace std;

// 圆形
template <typename T>
class Circle{
        T r;
public:
        Circle(T r):r(r){}
        float GetLength() const{
                return 2*M_PI*r;
        }
        float GetArea() const{
                return  M_PI*r*r;
        }
};

int main(){
        Circle<int> a(2);         // 必须定义参数类型
        cout << a.GetLength() << "," << a.GetArea() << endl;

        Circle<double> b(2.2);
        cout << b.GetLength() << "," << b.GetArea() << endl;
}

结果为:

12.5664,12.5664
13.823,15.2053

逐个创建数组并打印

#include <iostream>
using namespace std;

template <typename T>        // 模板
class SeqList{
        T* header;
        size_t count;
public:
        SeqList():header(NULL),count(0){}     // 构造函数
        // ~SeqList(){} 析构函数
        void Append(T val){          // 添加元素
                T* temp = new T[count+1];     // 申请一块儿新的连续的空间
                for(int i=0;i<count;++i){     // 把原来的部分复制进来
                        temp[i] = header[i];
                }
                temp[count] = val;        // 把新加的数放到后面   
                ++count;              // 数据个数加一
                delete [] header;         // 把之前的空间释放掉
                header = temp;         // 头指针指向新的顺序表
        }
        size_t GetSize() const{return count;}       // 数据长度
        T Get(int i) {return header[i];}          // 某个元素的值
        T& operator[](int i){return header[i];}      // []运算符重载
};

int main(){
        {
        SeqList<int> arr;       // 使用模板类,需要加类型
        arr.Append(2);
        arr.Append(4);
        arr.Append(3);
        arr.Append(5);

        for(int i=0;i<arr.GetSize();++i){        // 逐个打印
                cout << arr.Get(i) << " ";
        }
        cout << endl;
        }

        {
        SeqList<float> arr;       // 使用模板类,需要加类型
        arr.Append(2.2);
        arr.Append(4.4);
        arr.Append(3.3);
        arr.Append(5.5);

        for(int i=0;i<arr.GetSize();++i){        // 逐个打印
                cout << arr[i] << " ";         // 这里使用[]运算符重载
        }
        cout << endl;
        }
}

结果为:

2 4 3 5 
2.2 4.4 3.3 5.5

3. 模板特化

3.1 函数模板特化

出现问题:比较字符串大小时会出现比较错误的情况

#include <iostream>
#include <sstream>
using namespace std;

template<typename T>
T Max(T a,T b){
        return a>b?a:b;
}

int main(){
        cout << Max("abcd","defg") << endl;
}

结果为:

abcd

比较错误的原因是:程序会按照地址进行比较,找出较大的那一个

解决方法:模板特化

#include <iostream>
#include <sstream>
#include <cstring>
using namespace std;

template<typename T>
T Max(T a,T b){
        return a>b?a:b;
}

// 模板特化
template<>
const char* Max(const char* a,const char* b){
        return strcmp(a,b)>0?a:b;
}

int main(){
        cout << Max("abcd","defg") << endl;
        // cout << Max(string("abcd"),string("defg")) << endl;
}

结果为:

defg

模板特化的作用
特殊处理的模板,指定具体的模板类型

3.2 类模板特化

#include <iostream>
#include <cmath>
using namespace std;

// 圆形
template <typename T>
class Circle{
        T r;
public:
        Circle(T r):r(r){}
        float GetLength() const{
                return 2*M_PI*r;
        }
        float GetArea() const{
                return  M_PI*r*r;
        }
};

// 模板特化
template<>
class Circle<int>{
        int r;
public:
        Circle(int r):r(r){}
        float GetLength() const{
                cout << "Circle<int>:" ;
                return 2*M_PI*r;
        }
        float GetArea() const{
                cout << "Circle<int>:" ;
                return  M_PI*r*r;
        }
};

int main(){
        Circle<int> a(2);       // 这里使用的就是模板特化的类
        cout << a.GetLength() << "," << a.GetArea() << endl;

        Circle<double> b(2.2);
        cout << b.GetLength() << "," << b.GetArea() << endl;
}

结果为:

Circle<int>12.5664,Circle<int>12.5664
13.823,15.2053

这个例子属于全特化

全特化:

  1. 声明一个模板空参数列表template<>
  2. 在类名称后面的<>中显示指定类型

偏特化:

  1. 在一个模板类参数列表不指定或者指定部分具体类型
  2. 在类名称后面的对应类型中显示指定该类型
template<typename T>
class Test<T,int>{};

4. 非类型模板参数

#include <iostream>
#include <cmath>
using namespace std;

template<typename T,int n>        // 非类型模板参数
void PrintArr(const T (&arr)[n]){        // 只针对数组的特殊写法
        for(int i=0;i<n;++i){
                cout << arr[i] << " ";
        }
        cout << endl;
}

int main(){
        int arr[] = {1,3,5,7};    // int [4]
        PrintArr(arr);          // 可以检测到数据数量

        char str[] = "abcd";    // char [5]
        PrintArr(str);

        float fs[] = {1.1,2.2,3.3};
        PrintArr(fs);          // PrintArr(const float (&arr)[3])
}

结果为:

1 3 5 7 
a b c d  
1.1 2.2 3.3

优化: 函数模板参数尽量使用引用类型 const &

  1. 对象内容不改变
  2. 对象是在函数外定义的

例如:

Circle(const T& r):r(r){}
const T& Max(const T& a,const T& b){

可以避免拷贝构造

template <typename T> 也可以写成 template <class T>

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值