☰
【纯干货】C++ 模板核心知识点 ——包含 面试高频坑(类型推导 / 实例化 / 分离编译)
2026/9/29 3:00:13 网站建设 项目流程

模板初阶

文章目录

  • 模板初阶
  • 1.模板有啥用
  • 2.概念
    • ‼️注意点:
  • 3.模板有几种
  • 4.函数模板
    • 4.1创造格式
    • 4.2两种用法
      • 直接用(隐式实例化)
        • 坑点:类型冲突
        • 解决方法:
      • 特殊表明(显式实例化)
        • 必须用显式实例化的情况:
    • 4.3特殊情况
      • 普通函数和 函数模板 同名
        • 强制使用模板:
  • 5.类模板
    • 5.1格式
    • 5.2成员函数的类外定义
    • 5.3使用(实例化)

1.模板有啥用

// 交换intvoidSwap(int&left,int&right){inttemp=left;left=right;right=temp;}// 交换doublevoidSwap(double&left,double&right){doubletemp=left;left=right;right=temp;}// 交换charvoidSwap(char&left,char&right){chartemp=left;left=right;right=temp;}

有了模板,可以让上面3个函数变成一个⬇️

template<classT>voidSwap(T&x,T&y){T tmp=x;x=y;y=tmp;}





2.概念

函数模板在使用时,编译器会根据你传入的类型,自动生成对应类型的具体函数/类。

两个细节:

  • 定义模板参数用typename和class是完全一样的,随便用哪个都行
  • 不能用struct代替class/typename

‼️注意点:

  • 模版不建议声明和定义分离到.h 和.cpp 两个文件,会出现链接错误 (实现Stack和list这种的时候)





3.模板有几种

  1. 函数模版
  2. 类模版





4.函数模板

4.1创造格式

template<class类型参数1,class类型参数2,...>返回值类型 模板名(形参表){函数体}

举例:

template<classT>voidSwap(T&t1,T&t2){T tmp=x;x=y;y=tmp;}



4.2两种用法

直接用(隐式实例化)

inta1=10,a2=20;doubled1=10.1,d2=20.2;Add(a1,a2);// 编译器自动推导T为intAdd(d1,d2);// 编译器自动推导T为double
坑点:类型冲突

Add(a1, d1); // 编译报错!(a1 是 int, d1 是 double)

解决方法:
  1. 强转:Add(a1, (int)d1); // 把double转成int或者Add((double)a1, d1); // 把int转成double
  2. 显示实例化⬇️



特殊表明(显式实例化)

Add<int>(a1,d1);// 强制T为intAdd<double>(a1,d1);// 强制T为double
必须用显式实例化的情况:

当编译器无法推导出模板参数类型时必须用:

template<classT>T*func1(intn){returnnewT[n];}intmain(){double*p1=func1<double>(10);//当编译器无法推导出模板参数类型时必须用显式实例化return0;}



4.3特殊情况

普通函数和 函数模板 同名

template<classT>TAdd(constT&left,constT&right){return(left+right);}intAdd(constint&left,constint&right){return(left+right)*10;}intmain(){inta1=10,a2=20;cout<<Add(a1,a2)<<endl;// 输出300,调用的是普通函数return0;}

输出300,调用的是普通函数


强制使用模板:
Add<int>(a1,a2);// 强制调用模板版本,输出30





5.类模板

5.1格式

template<classT1,classT2,...,classTn>class类模板名{类内成员定义}

举例:只是在类前面加了template<typename T>,然后把所有用到 int 的地方都换成了 T。

template<typenameT>classStack{public:Stack(intn=4):_array(newT[n]),_size(0),_capacity(n){}~Stack(){delete[]_array;_array=nullptr;_size=_capacity=0;}voidPush(constT&x);private:T*_array;size_t _capacity;size_t _size;};



5.2成员函数的类外定义

template<classT>voidStack<T>::Push(constT&x){if(_size==_capacity){T*tmp=newT[_capacity*2];memcpy(tmp,_array,sizeof(T)*_size);delete[]_array;_array=tmp;_capacity*=2;}_array[_size++]=x;}
  • 必须再写一遍template<class T>
  • 函数名前面要写成Stack<T>::Push,而不是Stack::Push‼️



5.3使用(实例化)

  • 只有显示实例化。
  • 实例化的结果才是真正的类 ,Stack<double>* p1和Stack<int>* p2是两个不同的类类型‼️
intmain(){// Stack st1;// 错误!Stack是类模板,不是真正的类// 正确!必须在尖括号里指定类型Stack<int>st1;// 存int的栈st1.Push(3);Stack<double>st2;// 存double的栈st2.Push(1.1);//new的方式Stack<double>*pst=newStack<double>;deletepst;return0;}





需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询