C++模板函数

目录

一、模板函数

1.概念

2.一般模板函数

 3.特化模板函数

二、模板类

1.概念

2.模板类(Queue,Stack)

2.1Queue

2.2Stack

3.成员模板函数 

3.模板类特化

3.1全特化

3.2偏特化

三、模板类AutoPtr

 1.构造函数

2.析构函数

3.拷贝构造函数

4.等号、->、*等运算符重载

5.主函数调用AutoPtr


一、模板函数

1.概念

        模板函数不是一个实在的函数,编译器不能为其生成可执行代码。定义模板函数后只是一个对函数功能框架的描述,当它具体执行时,将根据传递的实际参数决定其功能。

2.一般模板函数

        以一个简单的Swap函数为例,其功能为交换两个变量的值。

void Swap(int & x, int & y)
{
    int tmp = x;
    x = y;
    y = tmp;
}

        上面的代码能实现交换功能,但是只能交换整数型即int类型,那么如果要交换浮点型或者字符型又需要另外写以下代码。

//浮点型
void Swap(double & x, double & y)
{
    int tmp = x;
    x = y;
    y = tmp;
}
//字符型
void Swap(char & x, char & y)
{
    int tmp = x;
    x = y;
    y = tmp;
}

        为了减少我们的代码量,此时就可以使用模板函数。所谓“模板”,就是可以用一个模子做出多种类似的东西,那么模板函数就是可以用一个函数实现对多种类型值的操作。

        模板函数写法如下:

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

        还是以Swap函数为例,实现代码为:

#include <iostream>
using namespace std;
template<class T>
void Swap(T & x, T & y)
{
    T tmp = x;
    x = y;
    y = tmp;
}
int main()
{
    int n = 2, m = 8;
    Swap(n, m);  //编译器自动生成 void Swap (int &, int &)函数
    cout<<"n="<<n<<" "<<"m="<<m<<endl; 
	double f = 2.8, g = 8.2;
    Swap(f, g);  //编译器自动生成 void Swap (double &, double &)函数
    cout<<"f="<<f<<" "<<"g="<<g<<endl;
    char *a = "abc",*b = "def"; //编译器自动生成 void Swap (char &, char &)函数
    Swap(a,b);
    cout<<"a="<<a<<" "<<"b="<<b<<endl;
	return 0;
}

        仅靠一个模板函数便实现了整数型、浮点型和字符型三种类型值的交换,运行截图如下:

 3.特化模板函数

        尽管模板函数能够对多种类型值进行操作,但是不同类型值在有些操作时需要先进行一定处理即特化,比如字符型是无法直接进行大小比较的,但我们可以比较其字符串长短,下面我们以Compare函数为例。

#include <iostream>
#include <cstring>
using namespace std;
//函数模板
template<class T>
bool Compare(T t1,T t2){
    return t1==t2;
}

template<> //函数模板特化
bool Compare(char *t1,char *t2){
    return strcmp(t1,t2)==0;
}

int main(int argc, char* argv[])
{
    int a = 2;
    int b = 2;
    int c = 8;
    double d = 2.8;
    double e = 2.8;
    double f = 8.2;
	char str1[] = "abc";
    char str2[] = "abc";
    char str3[] = "def";
    cout<<Compare(a,b)<<endl;
    cout<<Compare(a,c)<<endl;
    cout<<Compare(d,e)<<endl;
    cout<<Compare(e,f)<<endl;
    cout<<Compare(str1,str2)<<endl;
	cout<<Compare(str1,str3)<<endl;
    return 0;
}

        如果类型值相等输出为1,反之则输出为0。运行截图如下:

         可见经过特化之后的Compare函数除了能对数值进行大小比较还可以对字符型进行比较操作。需要注意的是模板函数只有全特化,没有偏特化。

二、模板类

1.概念

        一个类模板(类生成类)允许用户为类定义个一种模式,使得类中的某些数据成员、默认成员函数的参数,某些成员函数的返回值,能够取任意类型(包括系统预定义的和用户自定义的)。

        如果一个类中的数据成员的数据类型不能确定,或者是某个成员函数的参数或返回值的类型不能确定,就可以将此类声明为模板,它的存在不是代表一个具体的、实际的类,而是代表一类 类。

2.模板类(Queue,Stack)

       模板类的作用和模板函数的相同,都是为了减少代码量方便操作,这里就不再赘述。

       模板类的写法:

template  <类型形参表>
 class  <类名>
 {     //类说明体  };
 template  <类型形参表>
 <返回类型> <类名> <类型名表>::<成员函数1>(形参表)
 {     //成员函数定义体  }
 template  <类型形参表>
 <返回类型> <类名> <类型名表>::<成员函数2>(形参表)
 {     //成员函数定义体  }
 …
 template  <类型形参表>
 <返回类型> <类名> <类型名表>::<成员函数n>(形参表)
 {     //成员函数定义体  }

        在C++标准库(STL)中有栈和队列的类模板,因此可以直接使用。

2.1Queue

        队列的特点:先进先出,只能对队头和队尾的元素进行操作。

        queue的函数组成主要有:

                queue.size():返回队列中元素个数;

                queue.push():会将一个元素置入queue中;

                queue.front():会返回queue内的第一个元素(也就是第一个被置入的元素);

                queue.back():会返回queue中的最后一个元素(也就是最后被插入的元素);

                queue.pop():会移除queue内的第一个元素(也就是第一个被置入的元素);

        使用队列,要先包含头文件 : #include<queue>

#include <iostream> 
#include <queue>
using namespace std;
int main(){
	
	queue<int> queue;
	int num;
	
	cout<<"入队:"; 
	
	for(int i = 1;i<10;i++){
		
		queue.push(i);
		cout<<queue.back()<<" ";
	}
	
	queue.empty()?cout<<endl<<"当前队列空":cout<<endl<<"当前队列非空"; 
	cout<<endl<<"队列内元素数:"<<queue.size()<<endl;
	cout<<"出队:";
	
	while(!queue.empty())
	{
		cout<<queue.front()<<" ";
		queue.pop();
	}
	
	queue.empty()?cout<<endl<<"当前队列空":cout<<endl<<"当前队列非空"; 
	
	return 0; 
}

运行截图:

2.2Stack

        栈的特点:先进后出,只能对栈顶的元素进行操作。

        stack的函数组成主要有:

                stack.push():往栈头添加元素;
                stack.pop():从栈头移除第一个元素;
                stack.top():返回栈顶元素;
                stack.empty():判断堆栈是否为空,栈空返回true,栈非空返回false;
                stack.size():返回堆栈的大小;

        使用栈之前,要先包含头文件 : #include<stack>

#include <iostream> 
#include <stack>
using namespace std;
int main(){
	
	stack<int> stack;
	int num;
	
	cout<<"入栈:"; 
	
	for(int i = 1;i<10;i++){
		cout<<i<<" ";
		stack.push(i);
	}
	
	stack.empty()?cout<<endl<<"当前栈空":cout<<endl<<"当前栈非空"; 
	cout<<endl<<"栈内元素数:"<<stack.size()<<endl;
	cout<<"出栈:";
	
	while(!stack.empty())
	{
		cout<<stack.top()<<" ";
		stack.pop();
	}
	
	stack.empty()?cout<<endl<<"当前栈空":cout<<endl<<"当前栈非空"; 
	
	return 0; 
}

运行截图:

3.成员模板函数 

        成员模板函数在使用时有以下需要注意的地方:

        普通类的成员函数模板不管是普通类还是模板类,成员函数都可以是函数模板,称为“成员函数模板”,但不可以是虚函数,否则编译器报错。
        类模板的模板参数必须用<>指定,成员函数模板(函数模板)的模板参数可以自动推导。
        类模板的成员函数(普通成员函数/函数模板)只有为程序所用时(代码对函数或函数模板进行调用时)才实例化。 如果某函数从未使用,则不会实例化该函数。

//普通类
class A{
public:
	template<class T>     //成员函数模板
	void myfunc(T tempVal)
	cout << tempval <<endl;
}
A a;
a.myfunc(3);//模板函数自动类型推断
            //编译器遇到这条语句,将函数模板实例化。模板,不使用,不实例化。


//类模板的成员函数模板
template<class C>
class A{
public:
	template<class T2> 
	A(T2 v1, T2 v2){
							//构造函数模板
	}					
	
	template<class T>      //成员函数模板
	void myfunc(T tempVal)
	cout << tempval <<endl;
	
	void myfpt(){
							//普通成员函数
	}
	
	C m_ic;
}
A<float> a(1,2);        //类模板的模板参数必须指定,函数模板自动推导。
A<float> a(1.1, 2.2); 
a.myfpt();  			//调用时,才实例化该函数

成员函数外部实现
	
	template<class C>		//先跟类模板的模板函数列表
	template<class T2> 		//构造函数自己的模板函数列表
	A<C>::A(T2 v1, T2 v2){
		cout << v1 << v2 << endl;		//构造函数模板
	}

3.模板类特化

        模板函数特化和模板类特化的区别:模板函数只能全特化,而模板类既有全特化又有偏特化。

3.1全特化

        全特化即对所有模板类型都进行特化。

#include <iostream>
using namespace std;

template<typename T1, typename T2>
class A{
        public:
                void function(T1 value1, T2 value2){
                        cout<<"value1 = "<<value1<<endl;
                        cout<<"value2 = "<<value2<<endl;
                }
};

template<>
class A<int, double>{ // 类型明确化,为全特化类
        public:
                void function(int value1, double value2){
                        cout<<"intValue = "<<value1<<endl;
                        cout<<"doubleValue = "<<value2<<endl;
                }
};

int main(){
        A<int, double> a;
        a.function(28, 28.8);
        return 0;
}                   

运行截图:

3.2偏特化

        偏特化即对模板类型做一些限制特化。

#include <iostream>
using namespace std;

template<typename T1, typename T2>
class A{
        public:
                void function(T1 value1, T2 value2){
                        cout<<"value1 = "<<value1<<endl;
                        cout<<"value2 = "<<value2<<endl;
                }
};

template<typename T>
class A<T, double>{ // 部分类型明确化,为偏特化类
        public:
                void function(T value1, double value2){
                        cout<<"charValue = "<<value1<<endl;
                        cout<<"doubleValue = "<<value2<<endl;
                }
};

int main(){
        A<char, double> a;
        a.function('a', 28.8);
        return 0;
}

运行截图:

三、模板类AutoPtr

 1.构造函数

template<class T>
AutoPtr<T>::AutoPtr(T* pData)
{
	m_pData = pData;
	m_nUser = new int(1);
}

2.析构函数

~AutoPtr()
	{
		decrUser();
	}
void decrUser();
template<class T>
void AutoPtr<T>::decrUser()
{
	--(*m_nUser);
	if ((*m_nUser) == 0)
	{
		delete m_pData;
		m_pData = 0;
		delete m_nUser;
		m_nUser = 0;
	}
}

3.拷贝构造函数

template<class T>
AutoPtr<T>::AutoPtr(const AutoPtr<T>& h)
{
	m_pData = h.m_pData;
	m_nUser = h.m_nUser;
	(*m_nUser)++;
}

4.等号、->、*等运算符重载

AutoPtr<T>& operator=(const AutoPtr<T>& h);
T* operator->()
{
	return m_pData;
}
T& operator*()
{
	return *m_pData;
}
const T& operator *()const
{
	return *m_pData;
}
const T* operator ->()const
{
	return m_pData;
}
template<class T>
AutoPtr<T>& AutoPtr<T>::operator=(const AutoPtr<T>& h)
{
	decrUser();
	m_pData = h.m_pData;
	m_nUser = h.m_nUser;
	(*m_nUser)++;
}

5.主函数调用AutoPtr

#include<iostream>
#include <vector>
#include "autoptr.h"
#include "CMatrix.h"
using namespace std;
int main()
{
    AutoPtr<CMatrix> h1;
    double data[6] = {1,2,3,4,5,6};
    h1->Create(2,3,data);
    cout << *h1 << endl;
    AutoPtr<CMatrix> h2(h1);
    (*h2).Set(0,1,10);
    cout << *h1 << endl << *h2;
}

运行截图:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值