1、什么是模板?

(1)可以这样来解释这个问题,例如当我们需要定义多个函数,而这个函数功能其实都是一样的,例如两个数相加的函数,

只是相加的两个数的类型不相同而已,这就导致我们需要定义多个函数;当我们使用了函数模板之后,我们只需要定义

一个函数模板,这个函数模板的功能就是实现两个数相加的操作,而且可以传入自己指定的数据类型,这样我们就不用定义

多个函数了,所以可以认为,模板就是一种可以产生一系列功能相同而数据类型不同的函数或者是类的 "机器"。

(2)模板的形式:函数模板、类模板

(3)模板的声明格式

函数模板:

template<typename 类型参数>

返回类型 函数名(模板形参表)

{

   函数体

  }

 template<class 类型参数>

返回类型 函数名(模板形参表)

{

函数体

}

类模板:

template <typename 类型参数>

  class 类名

  {

    类成员声明

  }

  或

  template <class 类型参数>

  class 类名

  {

    类成员声明

  }

在上面的template后面的参数可以是多个,也可以是一个,而且修饰词typename和class可以混用,可以认为他们两个关键字没有什么区别,都可以使用;

template后面的"<>"尖括号可以紧跟在template关键字后面,也可以用空格来隔开;

(4)需要注意的是:typename或者是class指定的是一种数据类型,其实除了可以指定数据类型之外,还可以指定某种数据类型的变量,例如下面的

template <typename 形参名,class 形参名,int 形参名,  double 形参名, ......> 

typename和class后面的表示的是某种数据类型的形参名,将来在使用模板函数的时候传入自己指定的数据类型;而int和double后面的表示的是

这种数据类型的变量,将来在使用模板函数的时候自己传入自己的变量。所以对于模板的形参总共就是分为这两类:类型形参和非类型形参。

2、模板函数和模板类的使用

函数模板定义及其使用:

 #include <iostream>
using namespace std; template <typename T> // 声明函数模板
static T Add1(T a, T b)
{
return (a + b);
} template <class T, int count> // 声明函数模板
static void Print(T a)
{
int i = ; for (i = ; i < count; i++)
cout << a << " ";
cout << endl;
} int main(void)
{
cout << Add1<int>(, ) << endl; // 使用模板函数
Print<int, >(); // 使用模板函数
return ;
}

类模板定义及其使用:

 #include <iostream>
using namespace std; template <typename T, int Ksize, int Kval>
class Array{
public:
Array(void); // 构造函数
~Array(void) { delete[]p_Arr; p_Arr = NULL; } // 析构函数 类内定义方式
void display(void);
private:
T *p_Arr;
}; template <typename T, int Ksize, int Kval> // 类外定义方式
Array<T, Ksize, Kval>::Array(void)
{
p_Arr = new T[Ksize];
int i = ; for (i = ; i < Ksize; i++)
p_Arr[i] = Kval;
} template <typename T, int Ksize, int Kval> // 类外定义方式
void Array<T, Ksize, Kval>::display(void)
{
int i = ; for (i = ; i < Ksize; i++)
cout << p_Arr[i] << " ";
cout << endl;
} int main(void)
{
Array<int, , > arr;
arr.display();
return ;
}

运行结果分别如下所示:

        

(1)对于模板函数的使用需要注意的是:我们需要在函数名之后添加一对尖括号,将需要传给函数模板的参数写进去: Add1<int>(10, 20);

但是其实不加 <int> 也是可以的,但是前提条件是函数的参数类型都是相同的,否则就会编译出错:

Add1(10, 20)         // 这样是可以的,因为10 和 20 数据类型相同

Add1(10, 20.0)      // 这就不行,数据类型不相同

(2)对于类模板需要注意的是:除了在类模板声明前加上 template <......> 之外,如果成员函数是在类内定义倒没什么可说的,如果是在类外定义的,那么就需要注意了:

每个在类外定义的所有成员函数之前都要加上 template <......>,而且函数名前面还要加上 <.....>,里面的内容是参数名,如下所示:

template <typename T, int Ksize, int Kval>      // 类外定义方式

Array<T, Ksize, Kval>::Array(void)  {  }

(3)通过类模板来定义一个类对象的时候也是和函数差不多,也是需要加上 <...>,将要传给类模板的参数写进去即可: Array<int, 10, 10> arr;

2、模板本身不会占用内存空间,而定义的模板函数或者是模版类才会占用内存空间。

3、函数模板与同名非模板函数也可以重载。

 #include <iostream>
using namespace std; template <typename T> // 声明函数模板
static T Add(T a, T b)
{
cout << "模板函数" << endl;
return (a + b);
} static int Add(int a, int b) // 普通函数
{
cout << "普通函数" << endl;
return (a + b);
} int main(void)
{
cout << Add(, ) << endl;
return ;
}

运行结果如下:从结构可以看出来,函数模板与同名非模板函数也可以重载,而且当我们调用函数的时候优先调用的是普通的函数,而不是模板函数。

4、在template语句和函数模板定义语句之间是不允许插入其他的语句,并且一个 template<....> 只能对应一个模板的声明,而不用使用一个 template<....> 来声明多个函数模板或者是类模板。

C++中函数模版与类模版的更多相关文章

  1. 为什么 c++中函数模板和类模板的 声明与定义需要放到一起?

    将模板的声明与定义写在一起实在很不优雅.尝试用“传统”方法,及在.h文件里声明,在.cpp文件里定义, 然后在main函数里包含.h头文件,这样会报链接错误.why!!!!!!!!!!!!! 这是因为 ...

  2. c++ 类模版、成员函数模版、函数模版 用法

    C++函数模版与类模版. template <class T> void SwapFunction(T &first, T &second){ }//函数模版 templa ...

  3. 类模版的static成员

    类模版中声明static成员 template <class T> class Foo { public: static size_t count() { ++ctr; cout < ...

  4. C++ 类模板三(类模版中的static关键字)

    //类模版中的static关键字 #include<iostream> using namespace std; /* 类模板本质上是c++编译器根据类型参数创建了不同的类, c++编译器 ...

  5. C++ 类模板二(类模版与友元函数)

    //类模版与友元函数 #include<iostream> using namespace std; template<typename T> class Complex{ p ...

  6. 初探C++类模版学习笔记

    类模板 实现:在定义类的时候给它一个或多个參数,这个些參数表示不同的数据类型.                              -->抽象的类. 在调用类模板时, 指定參数, 由编译系 ...

  7. 【转载】 C++多继承中重写不同基类中相同原型的虚函数

    本篇随笔为转载,原文地址:C++多继承中重写不同基类中相同原型的虚函数. 在C++多继承体系当中,在派生类中可以重写不同基类中的虚函数.下面就是一个例子: class CBaseA { public: ...

  8. Win32下 Qt与Lua交互使用(四):在Lua脚本中自由执行Qt类中的函数

    话接上篇.通过前几篇博客,我们实现在Lua脚本中执行Qt类中函数的方法,以及在Lua脚本中连接Qt对象的信号与槽. 但是,我们也能发现,如果希望在Lua脚本中执行Qt类的函数,就必须绑定一个真正实现功 ...

  9. VC6.0中重载操作符函数无法访问类的私有成员

    整理日: 2015年03月18日 在 C++ 中,操作符(运算符)可以被重载以改写其实际操作.同时我们可以定义一个函数为类的朋友函数(friend function)以便使得这个函数能够访问类的私有成 ...

随机推荐

  1. redis的maxmemory与maxmemory-policy关系

    如果redis配置了maxmemory和maxmemory-policy策略,则当redis内存数据达到maxmemory时,会根据maxmemory-policy配置来淘汰内存数据,以避免OOM.r ...

  2. php 文件上传$_FILES中error返回值详解

    用PHP上传文件时,我们会用程序去监听浏览器发送过来的文件信息,首先会通 过$_FILES[fieldName]['error']的不同数值来判断此欲上传的文件状态是否正常.$_FILES[field ...

  3. RK3288 红外遥控器增加自定义按键

    转载请注明出处:https://www.cnblogs.com/lialong1st/p/10071557.html CPU:RK3288 系统:Android 5.1 1.在 dts 中增加红外遥控 ...

  4. NLTK在自然语言处理

    nltk-data.zip 本文主要是总结最近学习的论文.书籍相关知识,主要是Natural Language Pracessing(自然语言处理,简称NLP)和Python挖掘维基百科Infobox ...

  5. 为eclipse安装python、shell开发环境和SVN插件

    http://www.crazyant.net/1185.html 为eclipse安装python.shell开发环境和SVN插件 2013/08/27 by Crazyant 暂无评论 eclip ...

  6. emacs之切换h/cpp配置

    emacsConfig/switch-file-setting.el (defun switch-c () (global-set-key (kbd "<C-return>&qu ...

  7. emacs之配置8,gdb调试设置

    emacsConfig/gdb-setting.el (global-set-key [(f5)] 'gud-go) (global-set-key [(f7)] 'gud-step) (global ...

  8. WinForm各浏览器内核控件

    WebKit.NET webkit-sharp CefSharp awesomium OpenWebKitSharp geckofx MozNet Web Component

  9. PHP调用OCX控件的具体方法

    需要设置php.ini文件,找到这行com.allow_dcom=true,把com组件支持启用 使用PHP调用OCX控件,本不是个难题,但现实中采用flash回避的方法更通用.真正使用ocx的不多, ...

  10. CommonDialog控件

    '要先单击“工程-部件”,显示“部件”对话框,将“Microsoft Common Dialog control 6.0(SP6)”选中,在工具栏就多出了一个CommonDialog控件图标,将其添加 ...