前言
最近在C++知识查漏补缺和巩固的过程中,遇到关于C++模板的问题,查看了C++ Primer这本书,对相关知识进行总结。(第一次尝试MarkDown编写,不知道效果怎么样)
泛型编程
泛型编程最初提出时的动机很简单直接:发明一种语言机制,能够帮助实现一个通用的标准容器库。所谓通用的标准容器库,就是要能够做到,比如用一个List类存放所有可能类型的对象这样的事。比如我们使用vector时,可以是vector、vector,还可以是我们自己定义的数据类型,这就是泛型编程的例子,即我们在编写程序(程序员或者是你编写)的时候,不需要知道具体的数据类型,在“使用的时候”由程序使用者给定相应的类型,为什么“使用的时候”要打引号,因为这样说有一点不严格,因为还有一种方法也能处理在编写程序时不需要知道类型的情况,那就是面向对象编程(OOP),这二者是有区别的:OOP能处理类型在程序运行之前都未知的情况,但泛型编程需要在编译的时候就知道类型,这一要求要早于OPP机制。
C++模板
- 1模板定义
使用关键字template,如函数模板定义:
template<typname T>
void Fun(void)
{
T a;
}
- 2模板编译
编译器一个模板定义时,它并不生成代码,因为这个时候编译器并不知道具体类型,只有当使用模板时(这时候程序使用者就会给定相应类型),编译器才会生成代码。这一特殊机制会造成相应的编程影响。
通常,我们在调用函数时,只需要知道该函数的声明(回想一下,是不是这样的?比如你在写C代码时,如果先写main函数,在其中调用一个函数,而这个函数的定义在main代码之后,则现在我们只需要在main之前声明该被调用的函数,就可以了)。但是我们在使用类对象是,必须已经对该对象进行了定义,同样,我们也不必知道该类对象成员函数的定义,只需要声明(这个声明在哪里呢?就在类的定义里面)。所以,一般我们会把类的定义和普通函数的声明放在.h文件中,而把普通函数和类成员函数的定义放在相应的.cpp文件中。
但是对于模板程序来说,这一做法不行。普通模板函数的定义、模板类和其成员函数的定义,都需要放在.h文件中,不然编译就会报错。如下程序演示:
如头文件如下(类定义):
#include <iostream>
#include <conio.h>
const int SIZE=8;
template <class T>
class Smemory
{
T data[SIZE];
int count;
public:
Smemory(){ count=0; }
void mput(T x);
T mget( );
};
相应源文件(成员函数定义):
#include "ClassTemplateTest.h"
//定义成员函数mput(),函数的参数类型为T,该函数用于为数据成员 data数组的各个元素赋值
template <class T>
void Smemory<T>::mput(T x)
{
if(count==8) { cout<<"Memory is full"; return; }
data[count]=x;
count++;
}
//定义成员函数mget(),函数的返回类型为T,该函数用于取出数据成员 data数组的各个元素
template <class T>
T Smemory<T>::mget()
{
if(count==0) { cout<<"Memory is empty"; return 0; }
count--;
return data[count];
}
main函数为:
#include <iostream>
#include <string.h>
#include "ClassTemplateTest.h"
using namespace std;
void main()
{
Smemory<int> mo1;
int i;
char ch='A';
Smemory<char> mo2;
for(i=0;i<8;i++)
{
mo1.mput(i);
mo2.mput(ch);
ch++;
}
cout<<"Get mo1 => ";
for(int i=0;i<8;i++)
cout<<mo1.mget( );
std::cout<<"\nGet mo2 => ";
for(i=0;i<8;i++)
cout<<mo2.mget( );
_getch();
}
则报错:
而把成员函数放在.h文件就顺利编译通过,可自行验证。
模板实例化
对于类模板,不同的模板类型参数,会实例化不同的类对象,即一个类模板的每个实例都形成一个独立的类。另外,一个类模板的成员函数只有当程序用到它是才进行实例化,如对于上述出现编译错误的情况,如果在main函数中,没有调用mo2.mput()函数,则不会出现该函数的编译错误,即程序在编译过程中并没有生成该函数的实例化代码。