栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

c++(24)STL:函数模板、类模板

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

c++(24)STL:函数模板、类模板

我们在C语言的常规编程工作中,经常会遇到因为形参数据类型,而定义多个函数。比如功能交换A和B的值

//int 类型数据交换
void MySwap(int &a, int &b)
{
	int temp = a;
	a = b;
	b = temp;
}

//double 类型数据交换
void MySwap(double &a, double &b)
{
	double temp = a;
	a = b;
	b = temp;
}

只要A和B 这两个数据的类型不同,我就要重定义一个新函数,而这两个函数除了形参数据类型不一样,其他的逻辑都是一样的。这样就造成了代码的重复,增加维护成本。

为了解决这个问题,c++引入了 模板。

1、函数模板的基本语法

函数模板使形参类型化,实现定义的时候不关心具体的数据类型,只关心功能的实现。

编译器为了与普通函数区分,使用关键字template。

template  
template 这两种使用方式表达的意思一样,根据习惯喜欢用哪个就用哪个。如果说需要使用多个类型的参数,那么也可以增加定义

template

#include 
#include 
#include 
using namespace std;

//template  // 
template //这两种方式都可以  //如果需要多个类型参数的时候,可以增加定义 
//template
//使用template模板函数的时候,当出现template关键字的时候,只对紧接着出现的函数名生效
void MySwap(T &a, T &b)
{
	T temp = a;
	a = b;
	b = temp;
}
//上面template的作用域消失

int main(void)
{
	int a = 10, b = 20;
	cout <<"a="<(c, d);
	cout <<"c="<#include 
#include 
#include 
using namespace std;

template 
T MyAdd(T a, T b)
{
	cout<<"函数模板"< 

 3、函数模板和普通函数在一起调用的规则

(1)、函数模板可以像普通函数那样被重载

(2)、c++编译器优先考虑普通函数   

                 MySwap(T a, T b);    MySwap(int a, int b); 当形参都是int时,优先考虑普通。

(3)、如果函数模板可以产生一个更好的匹配,那么选择模板

(4)、可以通过空模板实参列表的语法限定编译器只能通过模板匹配 

                 MySwap<>(a, b);限定只调用函数模板   

4、c++编译模板机制剖析

 当我们需要编译一个test.cpp的时候,他的一个编译过程大概是这样的。首先预编译器会先将宏定义进行展开,生成test.i文件,此时的这个 .i 文件我们还能看得懂。(通过编辑器打开,可以在最下面发现 宏定义展开后的代码)

g++ -E test.cpp -o test.i

之后编译器会将.i文件,进行翻译编译,生成汇编文件test.s,这个时候已经不太能 看得懂了,当然ABCD的字母还是看得懂。

 g++ -S test.i -o test.s

在之后汇编器,会将.s文件变成二进制文件,也就是目标文件,也就是test.o文件。(在windows下是.obj文件)

 g++ -c test.s -o test.o

最后到链接器,将很多.o文件和链接库文件,最后都合在一起,生成可执行文件。(linux可执行文件,文件名可自定义。windows下是.exe文件)。

g++ test.s -o a.out

 函数模板的机制,其实是编译器在编译阶段,对函数模板进行了翻译。将整个工程中,被调用的函数模板翻译成了普通函数。调用了N种数据类型的模板,就会生成N个不同名称的普通函数。

 下面我们来验证一下

#include 
#include 
#include 
using namespace std;

template  //注意没有分号
T MyAdd(T a, T b)
{
	return (a+b);
}

int main(void)
{
	int nVal1 = 10, nVal2 = 20;
	char chVal1 = 30, chVal2 = 40;
	float fVal1 = 6.66, fVal2 = 9.99;
	
	MyAdd(nVal1, nVal2);
	MyAdd(chVal1, chVal1);
	MyAdd(fVal1, fVal2);
	
	MyAdd(nVal1, nVal1);
	
	return 0;
}


上面这个例子一共调用了四次MyAdd模板,我们对源文件直接进行编译g++ -S test.cpp -o test.s,生成 .s 文件。然后直接打开.s文件进行分析

.s文件还是能让我们稍微看懂一点,但是对与理解原来有很大帮助。我们看到里面有一个熟悉的main函数,在这里面call了四次 MyAdd,我们在.s里也发现了熟悉的MyAdd,只不过名字不太一样,多了一点后缀。

分别叫 细心点可以发现,里面不同的i、c、f、i就是  对应的数据类型的缩写,int、char、float、int。跟我们实际的调用情况也吻合。

5、函数模板案例char,int,float数据排序
#include 
#include 
#include 
using namespace std;

template  
void MySort(T *a, int len)
{
	int i=0, j=0;
	cout<<"排序之前的数据:"< 
 
6、类模板 

类模板和函数模板很相似,有一点区别。函数模板在调用的时候,可以自动类型推导。但是类模板必须显示的指定类型。

要注意在类模板派生普通类的时候,子类的定义也要指定数据类型。

类模板派生类模板的时候,如果不指定类型。那么需要再使用template关键字,定义模板类型。

#include 
#include 
#include 
using namespace std;

template  //注意没有分号
//类模板
class people
{
public:
	people(T age)
	{
		this->m_Age = age;
	}
public:
	T m_Age;
};

//类模板派生普通类
class student : public people
{
public:
};

//类模板派生类模板
template  //注意没有分号
class adult : public people
{
public:
	//类模板的,类内实现,需要指定模板类people
	adult(T age):people(age)
	{
	}
	
	void show();
};

//类模板的,类外实现,也需要指定模板类people
template  
void adult::show()
{
	//在类模板中使用成员变量,必须要加上this,或者指定类模板作用域,否则编译报错
	// adult::m_Age
	cout<<"i am adult, my age is "<m_Age< a1(30);
	a1.show();
	
	adult a2("30岁");
	a2.show();
	return 0;
}


这里一定要注意,使用类模板的时候,类内定义实现和类外定义实现的区别。其实如果对上面编译器的编译机制理解的比较好的话,就知道在分配内存的时候必要要指定类型,来区分内存大小。

当他是模板的时候,类型不明确。当变量不指定类型或者模板的时候,就更不知道具体的数据大小了。

 7、类模板重载操作符
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1024578.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号