C++模板深剖

传统艺能😎

小编是双非本科大一菜鸟不赘述,欢迎大佬指点江山(QQ:1319365055)
此前博客点我!点我!请搜索博主 【知晓天空之蓝】

🎉🎉非科班转码社区诚邀您入驻🎉🎉
小伙伴们,打码路上一路向北,背后烟火,彼岸之前皆是疾苦
一个人的单打独斗不如一群人的砥砺前行
这是我和梦想合伙人组建的社区,诚邀各位有志之士的加入!!
社区用户好文均加精(“标兵”文章字数2000+加精,“达人”文章字数1500+加精)
直达: 社区链接点我

🎉🎉🎉倾力打造转码社区微信公众号🎉🎉🎉
在这里插入图片描述


在这里插入图片描述

泛型编程🤔

C++ 又一个针对C语言不足提出的概念叫泛型编程,即我们的代码不再只是针对一种类型而是面对各种类型,它使用的基础就是C++的模板

我们实现一个场景时,很多代码是相似的,但我对于 int ,double,char ,不同的自义定类型都要去写一份代码,属实没有意思,所以C++给出了模板概念。比如古代印刷术出来之前,书的印刷是靠手抄,一遍一遍抄不仅慢还容易错字,古人就想出了将字刻在石板上雕版印刷即可,这就类似于模板。

模板是创建泛型类或函数的蓝图或公式。库容器,比如迭代器和算法,都是泛型编程的例子,它们都使用了模板的概念。

每个容器都有一个单一的定义,比如向量,我们可以定义许多不同类型的向量,比如 vector 或 vector 。

函数模板🤔

定义格式如下:

template<typename T,typename T2,……,typename Tn>

就拿简单的交换函数为例:

//template<class T>
template<typename T>//这里和class T没有区别
void Swap(T& a,T& b)
{
     T tem = a;
     a = b;
     b = tem; 
}//函数模板
int main()
{
     int a = 1,b = 2;
     float c = 1.11,d = 2.22;
     Swap(a,b);
     Swap(c,d);
}

注意 typename 是用来定义模板参数的关键字,也可以使用 class (切记不要使用 struct 代替 class)。这里可以看出函数模板类型一般是编译器根据显式传参将实参传给形参,推演出参数的类型

int Add(int a,int b)
{
   return a+b;
}
//通用加法函数
template Add<class T>
T Add(T a,T b)
{
   return a+b;
}

你说咱这个模板函数他又像函数又不像函数,他是不是函数呢?只能说是但不完全是,普通函数是可以声明和定义分开的,而模板是不能这么玩儿的,这样分开会链接报错,一般会放到一个文件中或者有些地方命名成 xxx.hpp,寓意就是头文件和定义实现内容合并到一起。

显示实例化指定🤔

为什么模板分开就不通过呢?原因就是符号表里面找不到,我们还是要敏感编译链接的过程,我们执行代码时,template.i 变成 template.s 编译完的时候就是空的,再变成 .o ,.exe 都是空的。编译器对 template 是下不了手的。链接时没能去找到函数模板调用的地址,因为类型里面还有没确定的那就是模板里面的这个 T ,.cpp 文件里面只包含了 .h ,没有对 T 的定义那么模板就是一个空壳子。

解决这个尴尬的情况的方法有吗?有!但是非常 low,归根结底造成这种情况的罪魁祸首是谁?是咱自己,是我们没有给出他的定义,我们此时就能采用显示实例化指定:

template
void Swap<int>(int& a,int& b);

template
Vector<int> v1;
Vector<double> v2;//整体实例化

所以解决方案就有两个:一是在 template.cpp 里面针对于要使用费=的模板类型显示实例化,二就是在不要分离的两个文件中,直接写在 xxx.hpp 或者 xxx.h 里面。相比之下第一种方法十分的复杂,因为有一种类型就得实例化一种类型,所以我们更倾向于第二种方法。

简单的指令交给我们去写了,真正复杂的交给编译器去实现了,这里面不仅仅只有简单的交换类型,它比你想象的更复杂。

类模板🤔

我们C语言不是有 typedef 吗,也可以应对各种类型,为啥要搞模板呢?很简单,如果我定义了一个栈结构,非递归实现时我要让 st1 用来存 int,st2 用来存 double 这是没办法做到的,typedef 要改就要全部改,而且 typedef 很麻烦还要自己改。

于是我们加入了类模板,我们类模板没有传参这个过程, :

template<class T,class T2,……,class Tn>
class
{
//成员定义
}

在类模板外部定义成员函数的方法为:

template<模板形参列表> 函数返回类型 类名<模板形参名>::函数名(参数列表){函数体}

比如定义一个的模板:

template
class Stack {
private:
vector member; // 成员
public:
void push(T const&); // 入栈
void pop(); //出栈
};
template
void Stack::push (T const& a)
{
member.push_back(member);
} //定义域内 push 函数

对于类模板,模板形参的类型必须在类名后的尖括号中明确指定。比如A<2> m;用这种方法把模板形参设置为int是错误的,类模板形参不存在实参推演的问题。也就是说不能把整型值2推演为int 型传递给模板形参。要把类模板形参调置为int 型必须这样指定A m。

说明一下本文是以C++初学者身份,所谓的深剖是相对初学者的深剖,不牵扯偏特化和继承。今天就到这里吧润了家人们。

  • 55
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 50
    评论
评论 50
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乔乔家的龙龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值