C++中template的简单用法
模板(Template)指C++程序设计设计语言中采用类型作为参数的程序设计,支持通用程序设计。C++ 的标准库提供许多有用的函数大多结合了模板的观念,如STL以及IO Stream。使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。
一、函数模板
在c++入门中,很多人会接触swap(int&, int&)这样的函数类似代码如下:
void swap(int&a , int& b) {
int temp = a;
a = b;
b = temp;
}
但是如果是要支持long,string,自定义class的swap函数,代码和上述代码差不多,只是类型不同,这个时候就是我们定义swap的函数模板,就可以复用不同类型的swap函数代码,函数模板的声明形式如下:
template<class 形参名, class 形参名,......> 返回类型 函数名(参数列表)
{ } template<typename 形参名, typename 形参名,......> 返回类型 函数名(参数列表)
{ }
swap函数模板的声明和定义代码如下:
//method.h
#pragma once
template <class T> void swap(T& t1, T& t2)
{
T tmp;
tmp = t1;
t1 = t2;
t2 = tmp;
}
上述是模板的声明和定义了,那模板如何实例化呢,模板的实例化是编译器做的事情,与程序员无关,那么上述模板如何使用呢,代码如下:
//main.cpp
#include <stdio.h>
#include "method.h"
int main() {
//模板方法
int num1 = , num2 = ;
swap<int>(num1, num2);
printf("num1:%d, num2:%d\n", num1, num2);
return ;
}
可以注意到,我将函数模板的声明和定义都放在了头文件中,一般来说,函数的声明放在头文件,其定义通常是放在源文件中的,这样在包含头文件时,可以有效避免出现重定义error。但模板的使用,需要实例化,而当实例化一个模板时,编译器必须看到模板确切的定义,而不仅仅是它的声明。(这一部分更多的解释可参考http://blog.csdn.net/lichengyu/article/details/6792135)
二、类模板
考虑我们写一个简单的栈的类,这个栈可以支持int类型,long类型,string类型等等,不利用类模板,我们就要写三个以上的stack类,其中代码基本一样,通过类模板,我们可以定义一个简单的栈模板,再根据需要实例化为int栈,long栈,string栈。
//stack.h
#pragma once
template<class T> class Stack {
public:
Stack();
~Stack();
void push(T t);
T pop();
bool isEmpty();
private:
T* m_pT;
int m_maxSize;
int m_size;
}; //同样,也把类模板中函数的定义写在.h文件中 //Define of Construct
template<class T> Stack<T>::Stack()
{
m_maxSize = ;
m_size = ;
m_pT = new T[m_maxSize];
} //Define of Destructor
template<class T> Stack<T>::~Stack()
{
delete[] m_pT;
} //Define of push()
template<class T> void Stack<T>::push(T t)
{
m_size++;
m_pT[m_size - ] = t;//数组下标从0开始
} //Define of pop()
template<class T> T Stack<T>::pop()
{
T t = m_pT[m_size - ];
m_size--;
return t;
} //Define of isEmpty();
template<class T> bool Stack<T>::isEmpty()
{
return m_size == ;
}
上述定义了一个类模板--栈,这个栈很简单,只是为了说明类模板如何使用而已,最多只支持100个元素入栈,使用示例如下:
#include <stdio.h>
#include "stack.h" int main()
{
Stack<int> intStack;
intStack.push();
intStack.push();
intStack.push(); while (!intStack.isEmpty())
{
printf("num:%d\n", intStack.pop());
}
return ; }
//num:3
//num:2
//num:1
三、模板参数
模板可以有类型参数,也可以有非类型参数(即内置类型参数),也可以有模板参数。
上述类模板的栈有一个限制,就是最多只能支持100个元素,我们可以使用模板参数配置这个栈的最大元素数,如果不配置,就设置默认最大值为100,代码如下:
//stack.h
#pragma once
//模板参数中使用内置的类型参数int,增加栈的最大容纳元素数
template<class T,int maxsize=> class Stack {
public:
Stack();
~Stack();
void push(T t);
T pop();
bool isEmpty();
private:
T* m_pT;
int m_maxSize;
int m_size;
}; //同样,也把类模板中函数的定义写在.h文件中 //Define of Construct
template<class T,int maxsize> Stack<T,maxsize>::Stack() //注意Stack<T,maxsize>中maxsize不要漏了
{
m_maxSize =maxsize;
m_size = ;
m_pT = new T[m_maxSize];
} //Define of Destructor
template<class T,int maxsize> Stack<T,maxsize>::~Stack()
{
delete[] m_pT;
} //Define of push()
template<class T,int maxsize> void Stack<T,maxsize>::push(T t)
{
m_size++;//增加元素的个数
m_pT[m_size - ] = t;//入栈,因为数组下标从0开始,所以-1
} //Define of pop()
template<class T,int maxsize> T Stack<T,maxsize>::pop()
{
T t = m_pT[m_size - ];
m_size--;
return t;
} //Define of isEmpty();
template<class T,int maxsize> bool Stack<T,maxsize>::isEmpty()
{
return m_size == ;
}
使用示例如下:
#include <stdio.h>
#include "stack.h" int main()
{
const int maxsize = ;
Stack<int,> intStack;
for (int i = ; i < maxsize; i++)
intStack.push(i); while (!intStack.isEmpty())
{
printf("num:%d\n", intStack.pop());
}
return ; }
//num:1023
//num:1022
//num:1021
//...
//...
//num:0
注:上述代码中template<class T,int maxsize=100> class Stack{};中int maxsize就是非类型的模板参数。有以下几点需要注意的:
1、非类型参数在模板定义的内部是常量值,也就是说非类型参数在模板的内部是常量;
2、非类型模板的参数只能是整型,指针和引用,像double,String,String **这样的类型是不允许的。但是double &,double *,对象的引用或指针是正确的;
3、调用非类型模板形参的实参必须是一个常量表达式,即它必须能在编译时计算出结果;
4、任何局部对象,局部变量,局部对象的地址,局部变量的地址都不是一个常量表达式,都不能用作非类型模板形参的实参。全局指针类型,全局变量,全局对象也不是一个常量表达式,不能用作非类型模板形参的实参。
5、全局变量的地址或引用,全局对象的地址或引用const类型变量是常量表达式,可以用作非类型模板形参的实参;
6、sizeof表达式的结果是一个常量表达死,也能用作非类型模板形参的实参。
C++中template的简单用法的更多相关文章
- Shellz中awk的简单用法
其实shell脚本的功能常常被低估.在实际应用中awk sed 等用法可以为shell提供更为强大的功能.下面我们将一下awk调用的简单方法进行了总结.方便同学们学习: awk的简单用法: 第一种调用 ...
- UltraEdit中使用正则表达式-简单用法
UltraEdit中使用正则表达式 1.认识正则表达式语法: 正则表达式 (UltraEdit Syntax): % 匹配行首 - 表明要搜索的字符串一定在行首. $ 匹配行尾 - 表明要搜索的字符串 ...
- C# Winfom 中ListBox的简单用法
https://www.cnblogs.com/xielong/p/6744805.html Winform控件ListBox的用法 1.如何添加listBox的值 this.listBox1.Ite ...
- (数据科学学习手札54)Python中retry的简单用法
一.简介 retry是一个用于错误处理的模块,功能类似try-except,但更加快捷方便,本文就将简单地介绍一下retry的基本用法. 二.基本用法 retry: 作为装饰器进行使用,不传入参数时功 ...
- java中printf()方法简单用法
%n 换行 相当于 \n %c 单个字符 %d 十进制整数 %u 无符号十进制数 %f 十进制浮点数 %o 八进制数 %x 十六进制数 %s 字符串 %% 输出百分号 > 在printf()方法 ...
- java 开发中 dom4j的简单用法
Java中处理XML的方式有很多种,个人任务dom4j还是比较好用的.下面介绍以下简单的使用方法 先把import补充上 import org.dom4j.Document; import org.d ...
- 转 jsp中 session的简单用法
Session对象:是用来分别保存每一个用户信息的对象,以便于跟踪用户的操作状态.Session的信息保存在服务端,Session的ID保存在客户机的Cookie中.事实上,在许多服务器上,如果浏览器 ...
- Android中AsyncTask的简单用法 .
在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行.在单线程模型中始终要记住两条法则: 1. 不要阻塞UI线程 2. 确保只 ...
- sqlhelper中事务的简单用法
sql1="INSERT INTO tablename(Id,col1,col2) VALUES(@Id,@col1,@col2) update tablename2 set col=@co ...
随机推荐
- 【转】CPU上下文切换的次数和时间(context switch)
http://iamzhongyong.iteye.com/blog/1895728 什么是CPU上下文切换? 现在linux是大多基于抢占式,CPU给每个任务一定的服务时间,当时间片轮转的时候,需要 ...
- 关于next.js中的css
css进行了全局和局部的限制 export default () => ( <div className='hello'> <p>Hello World</p> ...
- Eclipse集成Gradle 【Eclipse在线安装Gradle插件方法】
本章将介绍了Eclipse集成Gradle.以下是将Gradle插件添加到Eclipse的步骤. 步骤1 - 打开Eclipse Marketplace 打开在系统中安装好的Eclipse. 转到 J ...
- scala生态圈概览
相信很多朋友都对 Scala 这个结合了面向对象编程范式和函数式编程范式的编程语言新宠有所耳闻吧?!那么一旦你所在的项目选择了 Scala 的技术栈,还有哪些工具,类库可以选择呢?各种类型的框架或者类 ...
- git 合并连续的几个 commits
命令 git rebase -i HEAD~[N],如 git rebase -i HEAD~3 合并最近 3 个 commit. 运行上述界面后会进入一个编辑界面,快捷键是 vim 的快捷键. 修改 ...
- mysql5.6下载及安装(超级详细)
经过本人的实验,验证这些东西都是OK的 博客原文地址:http://www.cnblogs.com/Percy_Lee/p/5282187.html
- md5加密解密版本2
sklearn实战-乳腺癌细胞数据挖掘(博主亲自录制视频) https://study.163.com/course/introduction.htm?courseId=1005269003& ...
- Linux上安装Perl模块的两种方法
Linux/Unix下安装Perl模块有两种方法:手工安装和自动安装.第一种方法是从CPAN上下载 您需要的模块,手工编译.安装.第二种方法是联上internet,使用一个叫做CPAN的模块自动完 ...
- C语言指针详解(经典,非常详细)
前言:复杂类型说明 要了解指针,多多少少会出现一些比较复杂的类型,所以我先介绍一下如何完全理解一个复杂类型,要理解复杂类型其实很简单,一个类型里会出现很多运算符,他们也像普通的表达式一样,有优先级,其 ...
- docker入门(三)
docker容器IP"暴露"到外网(宿主机外) 首先将docker容器IP固定 Docker自身的4种网络工作方式,简略说明下: host模式,使用--net=host指定. co ...