当前位置:首页 » 《关于电脑》 » 正文

C++中的模版初识

11 人参与  2024年11月15日 13:21  分类 : 《关于电脑》  评论

点击全文阅读


目录

1.泛型编程

2.函数模板

什么是函数模板

如何定义函数模板

函数模板的原理

如何使用函数模板

隐式实例化

显示实例化

模板参数的匹配原则

3.类模板

如何定义类模板

如何使用类模板


1.泛型编程

所有的编程语言都具有各种各样的数据类型,不同数据类型的数据可能需要相同的功能。这个时候,如果是C语言的话,只能针对每种数据类型单独写一个函数,并且函数名还不能相同,如果是C++的话,虽然支持同名函数的出现,但是,也仅仅是函数名相同,针对不同的数据类型还是需要单独实现一个函数。于是,C++就引入了一种无关类型的编程方式 —— 泛型编程

在编程的世界中,不同类型的数据就好像是不同类型的原材料一般,在泛型编程的世界中,我们并不关心原材料的类型,不管你给我什么类型我都实现同样的功能;我们可以对比生活中的例子来理解,不知道大家有没有见过月饼的制作,过程大概如下:

用皮把馅料包起来。然后塞进模板。然后拍出来。

在这个过程中,模板并不关心是什么馅料,不管你是什么馅料,都能形成该卸料对应的月饼。没错,泛型编程也是如此,我们告诉编译器一个模板,编译器根据不同类型的数据利用该模板生成对应的代码。

在C++中,模板有两种,一种是函数模板,一种是类模板。(哦吼,这让我想起了友元函数和友元类)下面依次介绍

泛型编程:编写与类型无关的通用代码,是代码复用的一种手段,模板是泛型编程的基础。


2.函数模板

什么是函数模板

月饼模板是用来生产月饼的,那函数模板就是用来生产函数的。

函数模板是一个蓝图,本身并不是函数。

该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。


如何定义函数模板

使用格式如下:

template<typename T1, typename T2,......,typename Tn>
返回值类型 函数名(参数列表){}

template是定义模板的关键字typename是定义类型参数的关键字T1……Tn是模板参数其中,typename可以用class代替。

举个例子,实现一个通用的交换函数:

template<typename T>void Swap( T& left, T& right){T temp = left;left = right;right = temp;}

函数模板的原理

函数模板会根据参数类型生成特定版本的函数,这个工作是编译器来做的。在编译器编译阶段,调用函数模板的时候,编译器根据传入类型的参数推演实例化出该类型的函数。

以Swap函数为例:当我们传入int类型的数据时,编译器就会根据模板推演实例化出一份针对int类型的交换函数;如果传入的是char类型的数据,就会推演实例化出一份针对char类型的函数。


如何使用函数模板

函数模板并不是最终使用的函数,需要推演实例化出针对具体类型的函数才能使用,这个过程就叫做函数模板的实例化。实例化分为两种:隐式实例化显示实例化。

隐式实例化

隐式实例化就是让编译器根据实参推演模板参数的具体类型。

像这个例子中就是通过隐式实例化使用模板参数:

显示实例化

显示实例化的格式如下:

函数名 <类型> (参数)。其实就是在调用函数的时候,在函数后添加一对<>,并在<>中指明类型。

如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。

注意:前面示范的是单个模板参数的情况,多个模板参数的情况只需要类比函数参数使用即可。


模板参数的匹配原则

我们以 一个非模板函数和一个同名的函数模板同时存在为例,看下面这段代码:

// 专门处理int的加法函数int Add(int left, int right){return left + right;}// 通用加法函数template<class T>T Add(T left, T right){return left + right;}int main(){Add(1, 2); // 与非模板函数匹配,编译器不需要特化Add<int>(1, 2); // 调用编译器特化的Add版本    Add(1, 2.0); // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数return 0; }

我们可以这样理解,非模板函数是家里做的饭菜,函数模板生成的函数是外卖;可以形象的总结一下:

合适匹配的情况下,有现成的就吃现成。没有现成的,就点外卖吃。如果现成的不符合胃口,也点外卖。

注意,普通函数可以进行自动类型转换,函数模板不允许进行自动类型转换。(如果转换出来不是我们想要的,编译器就要背黑锅了,毕竟,谁都不愿意背黑锅)


3.类模板

C++中不仅仅有函数模板,还有类模板。比如:我们使用数据结构的时候,可能需要存储int类型的数据,可能需要存储char类型的数据,甚至需要存储自定义类型的数据,这个时候,不就又可以使用模板了吗?

如何定义类模板

定义类模板格式如下:

和函数模板的定义大差不差。 

我们以数据结构中的栈为例:

// 类模板template<class T>class Stack{public:Stack(int capacity = 4){cout << "Stack(int capacity = 4)" << endl;_arr = new T[capacity];_top = 0;_capacity = capacity;}~Stack(){cout << "~Stack()" << endl;delete[] _arr;_arr = nullptr;_top = 0;_capacity = 0;}private:T* _arr;int  _top;int  _capacity;};

当类模板的成员函数的声明和定义分离,且再同一个文件中的时候,需要再定义的前面加模板参数列表。

如下所示:

// 类模板template<class T>class Stack{public:        ~Stack();private:        T* _arr;        int  _top;        int  _capacity;};template<class T>Stack<T>::~Stack(){        cout << "~Stack()" << endl;        delete[] _arr;        _arr = nullptr;        _top = 0;        _capacity = 0;}

注意:类模板的声明和定义不能分在不同的文件,否则会造成链接错误。


如何使用类模板

类模板也是模板,使用的时候也需要进行推演实例化,只不过,类模板只能显示实例化。

并且,对于类模板来说,类名不是类型,类名+<模板参数类型> 才是类型

使用方式如下:

Stack<int> s1;Stack<double> s2;Stack<char> s3;

推演过程如下: 


点击全文阅读


本文链接:http://m.zhangshiyu.com/post/186536.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1