c++模板包含c++自带的stl,函数模板和类模板
1.stl
stl是标准模板库,比如list,vector,map等,使用方法就不说了,这里说下添加数据问题
假如添加内容为结构体TData,使用的是list,添加方法如下:
方法1:直接添加结构体
typedef list<TData> DATALIST;
DATALIST datalist ;
TData tData;
datalist .push_back(tData);
说明:stl里的push_back里会自动new一份,且如果传入的是类对象,在stl容量不足时,会自动扩容,并调用该类的拷贝构造函数,如果没有,则调用默认的拷贝构造函数(如A(&A)),默认拷贝构造函数只会拷贝值,不会分配内存
有兴趣的请自行搜索stl中push_back和浅拷贝和深拷贝的问题,原因终归是类写的有问题,解决办法是写类的时候,涉及到内存的记得加上拷贝构造函数,毕竟这类情况一旦出现很难定位
方法2:添加指针
typedef list<TData*> DATALIST;
DATALIST datalist ;
TData *ptData = new TData;
datalist .push_back(ptData );
错误使用情况:
TData tData;
datalist .push_back(&tData);
如果不使用new的情况,调试会发现里面所有数据都是相同的即第一个值的内容,原因暂不清楚,如果使用new内容才会正常
说明:
(1)stl使用时后面的<>里的跟的是数据类型,不要定义变量即<TData tData>
(2)方法2较方法1而言,在数据交互比较频繁的情况下会占用太多内存,而且要防止使用的上面的那种错误情况,方法1则不存在这些问题
2.函数模板
(1)格式:
template<class T>
void fun(T t)
{
}
或者
template<class T> void fun(T t)
{
}
两者是一样的,且template<class T> 和函数两者必须在一起,中间不能含有其他东西,如
template<class T>
int a = 0;
void fun(T t)
{
}
说明:c++中的函数模板,声明和定义要一起放在头文件中,因为函数模板并不是真正的函数,只有在使用的时候才会被实例化,如果一个放在.h中,一个放在.cpp中,不使用时编译不会报错,但是一旦使用,编译时就会提示“未定义的函数”错误
正确例子:
fun.h文件:
#ifndef _FUN_H_
#define _FUN_H_
template<class T> bool MAX_SIZE(T a, T b)
{
return a>b ? true:false;
}
#endif
(2)调用方式:隐式调用和显示调用
隐式调用:MAX_SIZE(2,3)
显示调用:MAX_SIZE<int>(2,3),其<>中的内容和数量要保持与templat<>中的一致
(3)函数模板支持重载,非模板参数,不支持默认模板参数
1>重载
template<class T> bool MAX_SIZE(T a, T b)
{
return a>b ? true:false;
}
bool MAX_SIZE(int a, char b)
{
return a>(int)b ? true:false;
}
说明:
函数模板内部不支持类型自动转化,无法处理传入参数不同的情况,可以通过重载的方式解决
2>非模板参数
template<class T, int nValue> bool MAX_SIZE(T a)
{
return a>nValue ? true:false;
}
使用:MAX_SIZE<int, 2>(3);
非模板参数类型只能显示调用
3>不支持默认模板参数
template<class T=int, int b> bool MAX_SIZE(T a)
{
return a>b ? true:false;
}
template<class T, int b=2> bool MAX_SIZE(T a)
{
return a>b ? true:false;
}
template<class T=int, int b=2> bool MAX_SIZE(T a)
{
return a>b ? true:false;
}
编译直接报错“仅允许在类模板上使用默认模板参数”
3.类模板
(1)格式:
template<class T>
class test
{
public:
test();
~test();
};
或者
template<class T> class test
{
public:
test();
~test();
};
正确例子:
classtest.h
#ifndef _TEM_H_
#define _TEM_H_
template<class T> class test
{
public:
test();
~test();
void show(T t);
private:
T m_t;
};
template<class T> test<T>::test()
{
}
template<class T> test<T>::~test()
{
}
template<class T> void test<T>::show( T t )
{
cout << t <<endl;
}
#endif//_TEM_H_
这里将声明和定义分开了,实际上大多数时候直接将实现内容放在类里,因为放在外面书写真的很麻烦
调用:
test<int> ctest;
ctest.show(2);
(2)类模板初始化静态成员
例子:
classtest.h
#ifndef _TEM_H_
#define _TEM_H_
template<class T> class test
{
public:
test();
~test();
static void showst()
{
cout << m_st <<endl;
};
private:
static T m_st;
};
#endif//_TEM_H_
如果你希望所有实例化的类静态值都一样,在上面类的大括号“}”下面加上:
template<class T> T test<T>::m_st = 0;
使用:
#include "stdafx.h"
#include "iostream"
#include "classtest.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
test<int> ctest;
ctest.showst();
system("pause");
return 0;
}
如果你希望每个实例化的类静态值不一样,那么声明的地方不要初始化,可以在使用这个类模板的cpp中初始化即可(只要在使用对应函数前初始化就行),如
#include "stdafx.h"
#include "iostream"
#include "classtest.h"
using namespace std;
template<> int test<int>::m_st = 1;
template<> long test<long>::m_st = 2;
int _tmain(int argc, _TCHAR* argv[])
{
test<int> ctest;
ctest.showst();
test<long> ltest;
ltest.showst();
system("pause");
return 0;
}
(3)c++类模板支持默认模板参数、inl文件
1>默认模板参数
如
template<class T=int,int nValue> class test
{
}
template<class T,int nValue=4> class test
{
}
template<class T=int,int nValue=4> class test
{
}
使用时用test<> ctest创建对象即可,上面第三个可以这样用,其他两个不全是默认参数,不能这样用
具体例子:
classtest.h
#ifndef _TEM_H_
#define _TEM_H_
template<class T=int> class test
{
public:
test();
~test();
void show(T t);
private:
T m_t;
};
template<class T> test<T>::test()
{
}
template<class T> test<T>::~test()
{
}
template<class T> void test<T>::show( T t )
{
cout << t <<endl;
}
#endif//_TEM_H_
使用:
#include "stdafx.h"
#include "iostream"
#include "classtest.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
test<> dtest;
dtest.show(3);
system("pause");
return 0;
}
2>inl文件
inl文件是内联函数源文件(存放内联函数的文件),在类模板里,如果实现过于复杂,可以将所有实现都放在inl文件里,在.h文件里用#include包含inl文件即可
classtest.h
#ifndef _TEM_H_
#define _TEM_H_
template<class T> class test
{
public:
test();
~test();
void show(T t);
static void showst();
private:
T m_t;
static T m_st;
};
#include "classtest.inl"
#endif//_TEM_H_
新建记事本txt文件,把实现内容都拷到txt里,另存为inl文件即可,inl文件头记得加#ifndef...,防止重复
classtest.inl
#ifndef _TEM_INL_
#define _TEM_INL_
template<class T> test<T>::test()
{
}
template<class T> test<T>::~test()
{
}
template<class T> void test<T>::show( T t )
{
cout << t <<endl;
}
template<class T> void test<T>::showst()
{
cout << m_st <<endl;
}
#endif//_TEM_INL_
(4)类模板里包含函数模板
classtest.h
#ifndef _TEM_H_
#define _TEM_H_
template<class T> class test
{
public:
test();
~test();
template<class V> void fun(V v)
{
cout << "v:" << v <<endl;
}
};
#endif//_TEM_H_
#include "stdafx.h"
#include "iostream"
#include "classtest.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
test<int> dtest;
dtest.fun<int>(5);
system("pause");
return 0;
}
类模板支持默认参数,类模板中函数模板同样不支持默认参数
(5)类模板的声明
c++中一个普通的类如class A,声明时直接在使用的头文件中加class A即可,如果是类模板实例化后,则对应的声明是在前面加一个template即可
如:template class test<int>;//类声明的格式,不是template<> class test<int>,容易犯错误的就是这里