一、类模板(Class Template)与模板类(Template Class)
简洁
类模板:模板 (用于生成类的模板)
模板类:实例 (由模板生成的类)
详细
类模板是一个蓝图,它不是具体的类,而是用来创建类的一种模型或框架。
类模板允许你定义函数和成员变量的数据类型作为模板参数typename T
或 class T
,这样就可以根据需要使用不同的数据类型来创建类。
说白了,类模板就是用T 作为类里面变量和成员函数参数的数据类型的占位符。模板类就是把占位符替换成实际数据类型(int,float等)后的类。
例子
#include <iostream>
using namespace std;
// 定义一个类模板
template <typename T>
class Box {
public:
// 构造函数
Box(T length, T width, T height) : length(length), width(width), height(height) {}
// 成员函数,计算体积
T volume() const {
return length * width * height;
}
private:
T length; // 长度
T width; // 宽度
T height; // 高度
};
int main() {
// 使用 int 类型实例化 Box 模板
Box<int> intBox(5, 4, 3);
cout << "Integer Box Volume: " << intBox.volume() << endl;
// 使用 float 类型实例化 Box 模板
Box<float> floatBox(5.5, 4.4, 3.3);
cout << "Float Box Volume: " << floatBox.volume() << endl;
return 0;
}
说明:
template<typename T> 和 template<class T>等价
在C++的Template中很多地方都用到了typename与class这两个关键字,有时候这两者可以替换,那么这两个关键字是否完全一样呢?
事实上class用于定义类,在模板引入c++后,最初定义模板的方法为:template<class T>,这里class关键字表明T是一个类型,后来为了避免class在这两个地方的使用可能给人带来混淆,所以引入了typename这个关键字,它的作用同class一样表明后面的符号为一个类型,这样在定义模板的时候可以使用下面的方式了:
template<typename T>,在模板定义语法中关键字class与typename的作用完全一样
函数模板(function template)和模板函数(template function)
简洁
函数模板:模板 (用于生成函数的模板)
模板函数:函数 (函数模板实例化后生成的函数)
详细
函数模板(function template)和模板函数(template function)是C++中泛型编程的重要组成部分,它们允许编写可以处理不同数据类型的函数,而无需为每种类型单独实现。
函数模板是指定义一个通用的函数结构,提供了一种方式来创建一组相关的,执行相同的操作但参数数据类型不同的函数。
例子
template <typename T>
void fun(T a)
{
…
}
在运用的时候,可以显式(explicitly)生产模板函数,fun <int> 、fun <double> 、fun <Shape*> ……。
也可以在使用的过程中由编译器进行模板参数推导,帮你隐式(implicitly)生成。
fun(6);//隐式生成fun <int>
fun(8.9);//隐式生成fun <double>
fun(‘a’);// 隐式生成fun <char>
Shape* ps = new Cirlcle;
fun(ps);//隐式生成fun <Shape*>
模板函数的重点是函数。表示的是由一个模板生成而来的函数。例子:
上面显式(explicitly)或者隐式(implicitly)生成的fun <int> 、fun <Shape*> ……都是模板函数。
#include <iostream>
// 函数模板定义
template <typename T>
T max(T a, T b) {
return (a > b) ? a : b;
}
int main() {
// 使用函数模板处理int类型
int intMax = max(3, 7);
std::cout << "Max of 3 and 7: " << intMax << std::endl; // 输出:Max of 3 and 7: 7
// 使用函数模板处理double类型
double doubleMax = max(3.14, 2.71);
std::cout << "Max of 3.14 and 2.71: " << doubleMax << std::endl; // 输出:Max of 3.14 and 2.71: 3.14
// 使用函数模板处理std::string类型
std::string strMax = max(std::string("apple"), std::string("banana"));
std::cout << "Max of \"apple\" and \"banana\": " << strMax << std::endl; // 输出:Max of "apple" and "banana": banana
return 0;
}
函数指针和指针函数
简洁
函数指针:指向函数的指针,重点是指针
指针函数:返回指针的函数,重点是函数
详细
1.函数指针——指针函数
函数指针的重点是指针。表示的是一个指针,它指向的是一个函数,例子:
int (*pf)();
指针函数的重点是函数。表示的是一个函数,它的返回值是指针。例子:
int* fun();
数组指针和指针数组
简洁
数组指针:指向的是一个数组的指针,重点是指针
指针数组:元素是指针的数组,重点是数组
详细
数组指针的重点是指针。表示的是一个指针,它指向的是一个数组,例子:
int (*pa)[8];
指针数组的重点是数组。表示的是一个数组,它包含的元素是指针。例子;
int* ap[8];
C++的函数模板和类模板|普通参数模板、类参数模板
2012-09-06 11:30:36
非类型(普通)参数模板
template <class T, int size,int size2 >
void f(char a)
{
char temp[size];
char temp[size2];
......
}
void main()
{
f<10,10>(1);
}
类型参数模板
简介:
//类声明
template<class T1, class T2>
class VarToVar
{
private :
T1 m_source_vars_list;
T2 m_dest_vars_list;
public:
int Add(T1 source_node, T2 dest_node);
VarToVar();
virtual ~VarToVar();
};
详细:
理解这个 typedef double Type; 有助于理解模板, Type就代表了double,Type data 相当于 double data。
1、函数模板
函数模板的用途:
类属函数指一个函数对不同类型的数据完成相同的操作。
1、宏实现
#define max(a,b) ((a)>(b)?(a):(b))
不足之处:只能实现简单的功能,并且存在不作类型检查以及重复计算等问题。
2、函数重载
int max(int,int);
double max(double,double);
A max(A,A);
不足之处:需要定义的重载函数太多,如果定义不全会有问题。
如:
cout << max(‘3’,’5’); 将输出53而非‘5’。
3、指针实现
例:编写一个排序(sort)函数,使其能对各种数据进行排序(整型数序列、浮点数序列以及某个类的对象序列等)。
void sort(void *base, //需排序的数据首地址
unsigned int count, //数据元素的个数
unsigned int element_size, //数据元素的大小
int (*cmp)(void *, void *) //比较两个数据元素
//大小的函数指针
)
{
//取第i个元素
(char *)base + i *element_size
//比较第i个和第j个元素的大小
(*cmp)((char *)base + i * element_size,
(char *)base + j * element_size
)
//交换第i个和第j个元素
char *p1 = (char *)base + i * element_size,
*p2 = (char *)base + j * element_size;
for (k = 0; k < element_size; k++)
{
char temp = p1[k];
p1[k] = p2[k];
p2[k] = temp;
}
}
int int_compare(void *p1, void *p2)
{
if (*(int *)p1 < * (int *)p2)
return –1;
else if (*(int *)p1 > *(int *)p2)
return 1;
else
return 0;
}
int double_compare(void *p1, void *p2)
{
if (*(double *)p1 < * (double *)p2)
return –1;
182
else if (*(double *)p1 > *(double *)p2)
return 1;
else
return 0;
}
int A_compare(void *p1, void *p2)
{
if (*(A *)p1 < * (A *)p2) //类A需重载操作符:<
return –1;
else if (*(A *)p1 > *(A *)p2) //类A需重载操作符:>
return 1;
else
return 0;
}
…
int a[100];
sort(a, 100, sizeof(int), int_compare);
double b[200];
sort(b, 200, sizeof(double), double_compare);
A c[300];
sort(c, 300, sizeof(A), A_compare);
不足之处:需要定义额外的参数,并且有大量的指针运算,使得实现起来麻烦、可读性差。
例:上述的排序用函数模板来实现。
template <class Type>
Type min( Type a, Type b ) ?
{
return a < b ? a : b;
}
Type统包了:int、float、double、string、char 等等类型,具体是哪一类,看实际引用,这就不必为每一个类型的数据都写一个函数了。
template <class T> //定义一个通用的参数T ,这个T指代哪种类型,视实例化为哪种类型
void sort(T elements[], unsigned int count)
{
//取第i个元素
elements [i]
//比较第i个和第j个元素的大小
elements [i] < elements [j]
//交换第i个和第j个元素
T temp = elements [i];
elements [i] = elements [j];
elements [j] = temp;
}
......
int a[100];
sort(a, 100);
double b[200];
sort(b, 200);
A c[300]; //类A中需重载操作符:<和=,给出拷贝构造函数
sort(c, 300);
函数模板定义了一类重载的函数,使用函数模板所定义的函数(模板函数)时,编译系统会自动把函数模板实例化。
模板的参数可以有多个,用逗号分隔它们,如:
template <class T1, class T2> //T1\T2 代表::int、float、double、string、char 等等类型
void f(T1 a, T2 b)
{ ......
}
模板也可以带普通参数(非类型参数<非代表类型的参数>因为已经具体指明了参数类型)),它们须放在类型参数的后面,调用时需显式实例化,如:
template <class T, int size>
void f(T a)
{
T temp[size];
......
}
void main()
{
f<int, 10>(1);
}
有时,需要把函数模板与函数重载结合起来用,例如:
template <class T>
T max(T a, T b)
{
return a > b ? a : b;
}
…
int x, y, z;
double l, m, n;
z = max(x, y);
l = max(m, n);
问题:max(x,m)如何处理?
定义一个max的重载函数:
double max(int a, double b)
{
return a > b ? a : b;
}
VC template模板的使用 类模板
//类声明
template<class T1, class T2>
class VarToVar
{
private :
T1 m_source_vars_list;
T2 m_dest_vars_list;
public:
int Add(T1 source_node, T2 dest_node);
VarToVar();
virtual ~VarToVar();
};
//函数实现体
template<class T1, class T2>
VarToVar<T1, T2>::VarToVar()
{
}
template<class T1, class T2>
VarToVar<T1, T2>::~VarToVar()
{
}
template<class T1, class T2>
int VarToVar<T1, T2>::Add(T1 source_node, T2 dest_node)
{
return FALSE;
}
//调用
VarToVar<int, int > a; //用int 模板的类 示例化 a
a.Add(3,4);
http:///blog/static/1618604420083167842277/
几点注意
① 如果在全局域中声明了与模板参数同名的对象函数或类型,则该全局名将被隐藏。
在下面的例子中tmp 的类型不是double 是模板参数Type
typedef double Type;
template <class Type>
Type min( Type a, Type b )
{
//tmp类型为模板参数?Type
//不是全局?typedef
Type tmp = a < b ? a : b;
return tmp;
}
② 在函数模板定义中声明的对象或类型不能与模板参数同名
template <class Type>
Type min( Type a, Type b )
{
//错误:重新声明模板参数?Type
typedef double Type;
Type tmp = a < b ? a : b;
return tmp;
}
③ 模板类型参数名可以被用来指定函数模板的返回位
// ok: T1 表示 min() 的返回类型
// T2 和 T3 表示参数类型
template <class T1, class T2, class T3>
T1 min( T2, T3 );
④ 模板参数名在同一模板参数表中只能被使用一次,但是模板参数名可以在多个函数模板声明或定义之间被重复使用
// 错误: 模板参数名 Type 的非法重复使用
template <class Type, class Type>
Type min( Type, Type );
// ok: 名字 Type 在不同模板之间重复使用
template <class Type>
Type min( Type, Type );
template <class Type>
Type max( Type, Type );
⑤ 如果一个函数模板有一个以上的模板类型参数则每个模板类型参数前面都必须有关键字class 或typename
// ok:关键字typename和class可以混用
template <typename T, class U>
T minus( T *, U );
//错误:必须是?<typename T, class U>或<typename T, typename U>
template <typename T, U>
T sum( T *, U );
⑥ 为了分析模板定义编译器必须能够区分出是类型以及不是类型的表达式对于编译器来说它并不总是能够区分出模板定义中的哪些表达式是类型例如如果编译器在模板定义中遇到表达式Parm::name 且Parm 这个模板类型参数代表了一个类那么name 引用的是Parm 的一个类型成员吗.
template <class Parm, class U>
Parm minus( Parm *array, U value )
{
Parm::name *p;
// 这是一个指针声明还是乘法乘法
}
编译器不知道name 是否为一个类型因为它只有在模板被实例化之后才能找到Parm 表示的类的定义为了让编译器能够分析模板定义用户必须指示编译器哪些表达式是类型表达式告诉编译器一个表达式是类型表达式的机制是在表达式前加上关键字typename 例如如果我们想让函数模板minus()的表达式Parm::name 是个类型名因而使整个表达式是一个指针声明我们应如下修改
关键字typename 也可以被用在模板参数表中以指示一个模板参数是一个类型
template <class Parm, class U>
Parm minus( Parm* array, U value )
{
typename Parm::name * p; // ok: 指针声明
}
⑦ 如同非模板函数一样函数模板也可以被声明为inline 或extern 应该把指示符放在模板参数表后面而不是在关键字template 前面
// ok: 关键字跟在模板参数表之后
template <typename Type>
inline
Type min( Type, Type );