什么是模板
在编程中,对于各种不同 的数据类型,我们希望能提供一种功能相同的函数,而这些函数的区别仅仅是所处理的类型不同。这一功能
,我们在C语言中用宏定义来实现,而在C++语言中我们可以用函数重载来实现,但这两种方法各有弊病,于是,我们引入了一种更安全可靠的方法,就是使用函
数模板和类模板。
简单的说,模板是一种工具,使用它程序员可以建立具有通用类型的函数库和类库,这给编写软件带来了方便。
具体的说,模板是对类型的参数化,将一般程序处理的类型参数化,就可以使用这段程序处理某个类型范围内的若干种类型的对象。这就是参数化的多态性。即,
多个不同类型的对象的操作可以对应同一结构的实现。
模板的种类: 有函数模板和类模板
函数模板
:是对一组函数的描述,编译系统对所定义的函数模板不产生函数的代码。只是当编译系统在程序中发现有与函数模板向匹配的函数调用时,就生成一个模板函数,
该函数的函数体和函数模板相同。
函数模板实际上是一个通用的函数,它可以适应某个范围的不同类型对象的操作,这样做可以避免程序员的重复劳动。也可以增加程序的灵活性和安全性。某些情
况下,函数模板可以代替函数重载。
定义格式:
template <(参数化的类型名表)>
<类型> <函数名>(<参数表>)
{
函数体
}
template
是定义模板的关键字
参数化类型名表是模板参数表,如有多个表项用' ,'号分隔。 格式如下:
class
<标识符1> ,class <标识符2>,。。。。
标识符是函数中参数化的类型,这里用class
来定义,其含义是说明其后的标识符是参数化的类型名。
模板函数:是某个函数模板的一个实在函数。
函数模板定义的是模板函数的一种工具,模板函数是函数模板的一种实例化,即
一个函数模板可以生成多个重载的模板函数。 通过如下例子来说明:
#include
template< class T >
//函数模板的定义,有一个模板参数t,该函数实现求同一 类型的两数之和。
T Add(T a, T b)
{
return a+b;
}
void main()
{
int x1=1,y1=2;
double x2=2.2,y2=2.8;
char x3='m',y3='n'; //分别用int
double char 来替代T 即实现了模板函数
cout<<"add(x1,y1)="<
cout<<"add(x2,y2)="<
cout<<"add(x3,y3)="<
}
模板规范(Template Specifications)
Template Specifications
模板规范是一系列参数化的类或函数的定义集。
语法:
模板声明 :
template <模板参数列表 >
declaration
模板参数列表:
模板参数
模板参数列表, 模板参数
模板参数:
类型参数
参数声明
类型参数:
class 标识符
typename标识符
模板声明是一系列参数化的类或函数的定义集。
The template declaration specifies a set of
parameterized classes or functions.
模板参数列表是用逗号分隔的在模板体中使用的类型(以class identifier, typename identifier,或者
template
type的形式出现)或者非类型(non-type)。在声明域中必须是一个函数或类的声明。你可以象实例化一个普通类那样去实例化一个类模板,但是你必
须在尖括号中包括模板参数。调用一个功能化的模板不需要特需的语法。
在功能化的模板中,每个模板参数必须在函数的模板参数列表声明中至少出现一次。
模板参数列是一个参数列表,它被用在规定代码中的哪一部分将改变的模板函数之中。例如:
template< class
T, int i > class MyStack...
在这种情况下模板能够使用一个类型(class T)和一个常数参数(int
i)。模板将再构造函数中使用类型T和常数整型变量i。在MyStack类声明的主体中,你必须参考T标示符。
例如:
Examples
// Example of the template keyword
template class TestClass {
public:
char buffer[i];
T
testFunc(T* p1 );
};
template
T
TestClass::testFunc(T* p1) {
return
*(p1++)
};
// To create an instance
of TestClass
TestClass ClassInst;
下面的例子显示了怎样向一个模板传递一个参数:
template
class X {
};
template class T1, typename
T2>
class Y {
};
Y aY
typename关键字可以在模板参数列表中使用,下面的模板声明是一样的。
template< class T1, class T2 > class X...
template< typename T1, typename T2 > class X...
下面的模板参数形式是可行的:
template class
allocator {};
template
typename Allocator = allocator > class stack
{
};
stack MyStack;
Visual
C++支持在模板参数列表中模板参数的复用机制。例如,下面的代码是合法的:
class Y {...};
template class X1 {...};
template class X2 {...};
Y aY;
X1
x1;
X2 x2;
模板声明自身不会产生代码,它规定了类或函数系列,以及当被其他的代码引用时将要产生的函数或类。
模板声明具有全局或命名区域。
Visual C++执行模板定义的语法检查。Visual C++5.0
和后续的版本能够发现以前的版本不能发现的错误。编译程序现在能够检测到模板定义,但从不实例化的语法错误。
这儿有一个普通的错误列表,它们能够被Visual C++ 4.0编译器编译,但是不能够被Visual C++
5.0或以后的版本编译。
· 一个用户自定义类型在模板声明声明前就被使用,但是它的声明在模板的第一个实例化或使用之前。
· template class X {
· //...
· Data m_data; //Error Visual C++ 5.0 or
later, Data not defined
· };
·
· class
Data {...};
·
· void g() { X
x1; }
·
· 解决该问题,只需将类模板X移到数据声明之前。
·
成员函数是在类模板外声明的,而且它从不在类模板内声明。例如:
· template
class X {
· //no mf declared here
· };
·
· //This definition did not cause an
error with Visual
· //C++ 4.0, but it will cause
an error with Visual
· //C++ 5.0 or later
· //
· template void X::mf()
{...};
· 除了声明是类模板外,类标识将始终被认为是普通类。例如下面的用Visual C++
5.0或以后的版本而不是用Visual C++ 4.0生成的代码将产生一个错误:
·
template class X {
· friend
class Y; //Parsed as Y less-than
·
//T greater-than;
· Z
mf( ); //Parsed as Z less-than T
·
//greater-than;
· };
·
·
template class Y {...};
·
template class Z {...};
·
·
X x;
·
· 为了解决此问题,将Y和Z的声明放到X之前。
·
· template class Y {...};
·
template class Z {...};
·
template class X {...};
模板的特性是静态多态, 是编译时期的多态,
比如:
template
void fun(){}
fun(1);
fun(2.3);
编译器就只会给你生成个void fun()和void fun(), 这种检查是在编译时期进行的.
比如用这一特性来搞个compile time check, 也叫static check, 比如morden C++ design上的:
template
struct static_assert;
template <>
struct static_assert{};
就可以实现编译期间的assert;
static_assert<1 > 2>();
static_assert<2 < 3>();
摸板现在不支持实现和原型分开, 所以你只能把他们放在同一个文件中, 比如:
template
void fun();
template
void fun(){...}
或者直接
template
void fun(){...}
C++模板的制定三:部分制定C++类
类模板的多参语法如下:
template
class classname
{
……
};
T能是所有类型,上一节我们介绍了制定类模板,本节说一下类模板的部分制定,意思就是说只制定模板参数
的一部分,从而得到我们想要的目的,本节直接来描述其语法,我想信大家都不愿意我在这罗嗦,都想直接了解其语法。下面我们就看一个类模板部分制定的例子。
SpecTemplate类的原型如下:
template
class SpecTemplate
{
public:
SpecTemplate(T
t,P p):_valt(t),_valp(p){}
~SpecTemplate(){}
T
typeT(){return _valt;}
void
typeT(T& t){ _valt = t;}
void
display(){cout<<_valt<
……
private:
T
_valt;
P
_valp;
};
假设我们想制定SpecTemplate类的模板参数P,当P为string类型时,我们希望其相应的SpecTemplate类和通用的SpecTemplate类具有不同的功
能。这时需部分制定SpecTemplate类,部分制定示例如下:
template
class SpecTemplate
{
public:
SpecTemplate(T
t,int p):_valt(t),_valp(p){}
~SpecTemplate(){}
T
typeT(){return _valt;}
void
typeT(T& t){ _valt = t;}
void
display(){cout<<_valp<
……
private:
T
_valt;
int
_valp;
};
这样就完成了类模板的部分制定,从而实现
你特别的需求。这里只是举例,请大家千万别说这样有不没有意义什么的。我只希望大家能明白其用法即可。
注:目前的VC6.0尚不支持这种写法,但这是C++标准写法,如果要试请用BC或GCC编译器。
文章写的仓促,有错别字或错误请大家多批
评指出。谢谢大家的捧场,在下感激不尽,欢迎和大家交流 (-----袁凯-----)。
编写了一个很简单的类 stack
%2Fu%2F20091106%2F09%2F36be1c18-1f21-4afa-99d5-32008d079a42.html
源代码如下:
- C/C++ code
//类定义
template <class T>
class MyStack
{
public:
// class constructor
MyStack();
bool isempty() const;
bool isfull() const;
int countNum() const;
bool push(const T &item);
bool pop(const T &item);
// bool push(const Item &item);
// bool pop(Item &item);
private:
// enum {MAX = 10};
// Item items[MAX];
T items[10];
int top;
int nums;
};
// Class automatically generated by Dev-C++ New Class wizard
--------------------------------------------------------------------------------------------
//类实现
#include "mystack.h" // class's header file
// class constructor
template <class T>
MyStack<T>::MyStack()
{
// insert your code here
top=0;
nums=0;
}
template <class T>
bool MyStack<T>::isempty() const
{
return top==0;
}
template <class T>
bool MyStack<T>::isfull() const
{
return top==MAX;
}
template <class T>
int MyStack<T>::countNum() const
{
return nums;
}
template <class T>
bool MyStack<T>::push(const T &item)
{
if(top<MAX)
{
items[top++]=item;
nums--;
return item;
}
else
return false;
}
template <class T>
bool MyStack<T>::pop(const T &item)
{
if(top>0)
{
item = items[--top];
nums++;
return true;
}
else
return false;
}
-------------------------------------------
//main函数
#include <cstdlib>
#include <iostream>
#include "mystack.h"
using namespace std;
int main()
{
MyStack<int> iiu;
system("PAUSE");
return EXIT_SUCCESS;
}
编写可移植的C++ 模板代码(参考以下网址)
http://hi.baidu.com/dazhao_dbblog/blog/item/a12e093e39d13ceb55e72373.html
写了一个简单的c/c++模板类,共享大家
[code]
#include ;
#include ;
#include ;
#include ;
#include ;
#include ;
using namespace std;
class doctmplx
{
public:
doctmplx();
doctmplx(const string&);
~doctmplx();
int open(const char*);
int replace(char *src_str, char *dest_str);
int write(const string&);
void close();
protected:
string filex;
char *data;
};
doctmplx::doctmplx()
{
filex = "";
data = NULL;
}
doctmplx::doctmplx(const string &x)
{
filex = x;
data = NULL;
}
doctmplx::~doctmplx()
{
}
int doctmplx::open(const char *filename)
{
filex = filename;
FILE *fp;
char *buff;
long f_size;
fp=fopen(filename, "rb");
if(fp==NULL)
{
return -1;
}
fseek(fp, 0, 2);
f_size=ftell(fp);
rewind(fp);
buff=(char *)malloc(f_size+2);
fread(buff, 1, f_size, fp);
buff[f_size]='\0';
fclose(fp);
data = buff;
return 0;
}
int doctmplx::replace(char *str1, char *str2)
{
char *buff1, *p, *p1, *p2, *p3;
int i, len, alloc_size;
p1=data;
p3=data;
i=0;
while(1)
{
p2=strstr(p1, str1);
if(!p2) break;
p1=p2+strlen(str1);
i++;
}
if(i==0) return -1;
len=strlen(str2)-strlen(str1);
if(len>;0)
alloc_size=strlen(p3)+len*i+1;
else
alloc_size=strlen(p3)+1;
buff1=(char *)malloc(alloc_size);
for(i=0; i
for(i=0, p1=p3; ;)
{
p2=strstr(p1, str1);
if(!p2) break;
for(p=p1; p
for(p=str2; *p; buff1[i++]=*(p++));
p1=p2+strlen(str1);
}
for(p=p1; *p; buff1[i++]=*(p++));
free(p3);
data=buff1;
return 0;
}
int doctmplx::write(const string &filew)
{
ofstream out(filew.c_str());
if(!out.is_open())
return -1;
out << data;
return sizeof(data);
}
void doctmplx::close()
{
if(data != NULL)
free(data);
data = NULL;
}
int main(int argc, char *argv[])
{
doctmplx tmp;
tmp.open("tech.htm");
tmp.replace("$_ptitle1_", "这是一个测试");
tmp.replace("$_ptitle2_", "这是二个测试");
tmp.replace("$_ptitle3_", "这是三个测试");
tmp.replace("$_ptitle4_", "这是四个测试");
tmp.write("tech.html");
tmp.close();
}
[/code]
数据文件:
[code]
原文件:tech.htm
;
;
;
;
$_ptitle1_
$_ptitle2_
$_ptitle3_
$_ptitle4_
| ;
;
;
;
生成结果文件:tech.html
;
;
;
;
这是一个测试
这是二个测试
这是三个测试
这是四个测试
| ;
;
;
;
[/code]
阅读(800) | 评论(1) | 转发(0) |