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. 把CDLinux制作成U盘启动

    因为用下了CDlinux,本来想在虚拟机上运行的.发现虚拟机跑的时候无法识别集成的笔记本网卡,坑爹啊.后来想刻碟的,发现手头上还没有现成的东西,光驱是只读的,又要用到光驱,于是想到了了用U盘,正好手上 ...

  2. 使用_beginThreadex创建多线程(C语言版多线程)

    _beginThreadex创建多线程解读 一.需要的头文件支持 #include <process.h>         // for _beginthread() 需要的设置:Proj ...

  3. 关于oracle的profiles

    一.关于oracle的profiles profiles文件是口令和资源限制的配置集合,包括CPU的时间.I/O的使用.空闲时间.连接时间.并发会话数量.密码策略等对于资源的使用profile可以做到 ...

  4. Hive之 数据类型

    hive 目前支持的数据类型如下: -- 数值类型 Numeric TypesTINYINT (1-byte signed integer, from -128 to 127)SMALLINT (2- ...

  5. 生成.eps文件方法

    生成.eps文件方法 背景: 要写论文了,图像的分辨率是一大痛点 方法一: 两步生成.eps文件 用visio 制作图形,保存为pdf格式: 直接用adobe acrobat 打开pdf,然后保存为. ...

  6. unity里面查找所有物体

    测试的时候发现一个很诡异的bug,在prefab里面的物体的属性居然不断的在变化,最后一步步调试才发现,区别是查找物体的api,特此记录下 两种api Canvas[] canvasArray = ( ...

  7. 学习笔记之PHP

    学习 PHP,第 1 部分: 注册帐户.上传需要批准的文件.并查看和下载已批准的文件 https://www.ibm.com/developerworks/cn/opensource/tutorial ...

  8. 《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #13 使用Block I/O控制器设置I/O优先级

    HACK #13 使用Block I/O控制器设置I/O优先级 本节介绍使用Block I/O控制器的功能设置I/O优先级的方法.Block I/O控制器可以将任意进程分组,并对该分组设置I/O的优先 ...

  9. 好记性不如烂笔头-linux学习笔记4apache相关知识

    apache 启动有2种模式 1是prefork模式,每个进程对应一个线程,如果是比较稳定的平台,那么prefork模式是worker模式 比较好,效率高,但是吃的内存比较大. 2 如果是高负载高并发 ...

  10. mybatis 学习五 二级缓存不推荐使用

    mybatis 二级缓存不推荐使用 一 mybatis的缓存使用. 大体就是首先根据你的sqlid,参数的信息自己算出一个key值,然后你查询的时候,会先把这个key值去缓存中找看有没有value,如 ...