• C++基础:C++模板(Template)简介


     1、概述:

    模板(Template)是一种强大的C++软件复用特性,通常有两种形式:函数模板和类模板。函数模板针对仅参数类型不同的函数;类模板针对仅数据成员和成员函数类型不同的类。函数模板和类模板可以是程序员只需制定一个单独的代码段,就可表示一整套称为函数模板特化的相关(重载)函数或是表示一整套称为类模板特化的相关的类。这种技术称为泛型程序设计(generic programming)。

    使用模板的好处在于,可以使程序员编写与类型无关的代码。使用时要注意:模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。

    模板定义以关键字template开始,后接模板形参表,模板形参表是用尖括号括住的一个或者多个模板形参的列表,形参之间以逗号分隔。模板形参可以是表示类型的类型形参,也可以是表示常量表达式的非类型形参。非类型形参跟在类型说明符之后声明。类型形参跟在关键字class或typename之后定义。

     

    2、函数模板

             函数模板格式如下:

             template<typename T1,typename T1,…>函数名(参数列表){…}

      或 template<classT1,class T1,…>函数名(参数列表){…}

             其中尖括号内为模板形参列表,不能为空,但具体数目依需要而定。此处,typename和class关键字无区别。以下以一段代码示例简要说明使用。

    /*
    test for template
    */
    #include<iostream>
    using namespace std;
    template<class T>
    T findBigger(T &a, T &b)
    {	
    	return a>b ? a:b;
    }
    
    void main()
    {
    	int i1 = 10, i2 = 20;
    	double d1 = 1.1, d2 = 2.2;
    	cout<<"----------Test for template----------"<<endl;
    	cout<<"bigger one between "<<i1 <<" and "<<i2<<" is "<<findBigger(i1,i2)<<endl;//无需说明类型
    	cout<<"bigger one between "<<d1 <<" and "<<d2<<" is "<<findBigger(d1,d2)<<endl;
    	system("pause");
    }




    几点说明:

    • 模板形参名只能在模板头部的形参列表中声明一次,但是可以在函数头和函数体内重复使用;
    • 如果调用了一个带用户定义类型的模板,并且该模板用到了函数或运算符(如,==、+、<=),那么这些函数和运算符必须被这个用户定义类型重载。忘记重载这些函数和运算符会导致编译错误。

    3、类模板

    类模板格式与函数模板相似:

             template<typename T1,typename T1,…>class 类名{…}

    或 template<classT1,class T1,…> class 类名{…}

    依然以代码说明,定义了堆栈类Stack及其操作,并创建模板函数类测试。

    //Stack class template
    //Filename: Stack.h
    #ifndef STACK_H
    #define STACK_H
    
    template<class T>
    class Stack
    {
    private:
    	int size;
    	int top;
    	T *stackPtr;
    public:
    	Stack(int = 10);
    	~Stack()
    	{
    		delete []stackPtr;
    	}
    	bool push(const T &); //push an element onto the stack
    	bool pop(T &);//pop an element off the stack
    	bool isEmpty() const
    	{
    		return top==-1;
    	}
    	bool isFull() const
    	{
    		return top==size-1;
    	}
    };
    
    template<class T>
    Stack<T>::Stack(int n):size(n>0 ? n:10),top(-1),stackPtr(new T[size])
    {
    	//empty body
    }
    
    template<class T>
    bool Stack<T>::push(const T &value)
    {
    	if(!isFull())
    	{
    		stackPtr[++top] = value;
    		return true;
    	}
    	return false;
    }
    
    template<class T>
    bool Stack<T>::pop(T &value)
    {
    	if(!isEmpty())
    	{
    		value = stackPtr[top--];
    		return true;
    	}
    	return false;
    }
    #endif

    /*
    test for template
    */
    //Filename: templatetest.cpp
    #include<iostream>
    #include<string>
    #include"Stack.h"
    using namespace std;
    
    
    //创建模板函数来测试
    template<class T>
    void testStack( Stack<T> &theStack, T value, T increment ,const string stackName)
    {
    	cout<<"
    Pushing elements onto "<<stackName<<endl;
    	while(theStack.push(value))
    	{
    		cout<< value<< ' ';
    		value += increment;
    	}
    
    	cout<<"
    Stack is full now. Cannot push "<<value<<endl;
    	cout<<"
    Poping elements from "<<stackName<<endl;
    	while(theStack.pop(value))
    		cout<<value<< ' ';
    	cout<<"
    Stack is empty now. Cannot pop"<<endl;
    }
    
    int main()
    {
    	Stack<int> intStack(10);
    	Stack<double> doubleStack(8);
    
    	testStack(intStack, 2, 2, "intStack");
    	testStack(doubleStack, 1.1, 1.1 ,"doubleStack");
    	system("pause");
    	return 0;
    }

    结果截图:



    几点说明:
    • 以上示例Stack类模板只在模板头部使用了一个类型参数,可以使用多个。
    • 同样也可以使用非类型模板参数(或非类型参数),它可以有默认的参数并作为常量处理。例如,模板头部可以修改为包含一个 int elements 参数的形式,elements说明其Stack的大小,如下所示:
                 template<class T, int elements> //其中elements就是非类型参数,然后使用如下声明:
    Stack<double , 100> doubleStack; 实例化一个有100个double元素的doubleStack对象。
    • 另外,类型参数可以指定其默认类型,例如:
    template<class T = string> //Stack元素默认为string对象,然后可以使用如下声明:
    Stack< >stringStack; 来实例化一个string类型的Stack。
    • 要注意的是,默认参数必须放在模板参数列表的最右边(尾部)。当用两个或两个以上的默认类型初始化一个类似,其中一个默认参数不是在参数列表的最右边,那么该参数右边的所有参数都将被忽略。


  • 相关阅读:
    WPF鼠标拖放功能(拖放图片,文本)
    PHP封装属性
    vs 启动时报错:未能加载文件或程序集 SharpGit
    C#.NET Winform承载WCF RESTful API (硬编码配置)
    使用edge浏览器时,怎么让alt+tab不切换他的子标签页而只在程序间切换?
    C#.NET Winform使用线程承载WCF (硬编码配置)
    AnkhSVN For Visual Studio 2022
    ASP.NET MVC 查询加分页
    C#.NET Winform承载WCF RESTful API (App.config 方式)
    C#.NET Windows服务承载WCF
  • 原文地址:https://www.cnblogs.com/f8master/p/3826101.html
Copyright © 2020-2023  润新知