注意:本文中代码均使用 Qt 开发编译环境,如有疑问和建议欢迎随时留言。

模板是 C++ 支持参数化程序设计的工具,通过它可以实现参数多态性。所谓参数多态性,就是将程序所处理的对象的类型参数化,使得一段程序可以用于处理多种不同类型的对象。

函数模板

函数模板的定义形式是:

template <class T> // or template <typename T>
returnType functionName ( params ) {
// todo something
}

所有函数模板的定义都是用关键字 template 开始的,该关键字之后是使用尖括号 <> 括起来的类型参数表。每一个类型参数 T 之前都有关键字 class 或者关键字 typename,这些类型参数代表的是类型,可以是内部类型或自定义类型。这样,类型参数就可以用来指定函数模板本身的参数类型和返回值类型,以及声明函数中的局部变量。函数模板中函数体的定义方式与定义其它函数类似。

实例一

#include <QCoreApplication>
#include <QDebug> template < typename T >
T abs(T x) {
return x < 0 ? -x : x;
} int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv); int n = -5;
double d = -5.5;
qDebug() << abs(n);
qDebug() << abs(d);
qDebug() << abs(d+n); return a.exec();
}

运行结果:

运行结果

实例二

#include <QCoreApplication>
//#include <QDebug>
#include <iostream>
using namespace std; template <typename T> void outputArray(const T *P_aaray,const int count){
for(int i=0; i < count; i++) {
cout<<P_aaray[i]<<" ";
}
cout<<endl;
} int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv); const int aCount = 8, bCount= 8, cCount = 20;
int aArray[aCount] = {1,2,3,4,5,6,7,8};
double bArray[bCount] = {1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8};
char cArray[cCount] = "Welcometo see you!"; cout <<"a Array contains: "<<endl;
outputArray(aArray,aCount); cout <<"b Array contains: "<<endl;
outputArray(bArray,bCount); cout <<"c Array contains: "<<endl;
outputArray(cArray,cCount); return a.exec();
}

运行结果:

运行结果

函数模板几点注意

① 如果在全局域中声明了与模板参数同名的对象函数或类型,则该全局名将被隐藏。例如,在下面的例子中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 是个类型名因而使整个表达式是一个指针声明我们应如下修改:

template <class Parm, class U>
Parm minus( Parm* array, U value ) {
typename Parm::name * p; // ok: 指针声明
}

如上面的几个例子中所示,关键字 typename 也可以被用在模板参数表中以指示一个模板参数是一个类型。
⑦ 如同非模板函数一样,函数模板也可以被声明为 inline 或 extern 的。此时,应该把指示符放在模板参数表后面而不是在关键字 template 前面。

// ok: 关键字跟在模板参数表之后
template <typename Type>
inline
Type min( Type, Type );

类模板

使用类模板使用户可以为类声明一种模式,使得类中的某些数据成员、某些成员函数的参数、某些成员函数的返回值能取任意类型(包括系统预定义的和用户预定义的)。由于类模板需要一种或多种类型参数,所以类模板也常称为参数化类。

类模板声明的语法形式是:

template<模板参数表>
class类名{
//类成员声明
}

如果需要在类模板以外定义其成员函数,则需要采用以下形式:

template<模板参数表>
类型名类名<T>::函数名(参数表)

“模板参数表”由用逗号分隔的若干类型标识符或常量表达式构成,其内容包括:
(1)class 或 typename 标识符,指明可以接受一个类型的参数。
(2)类型说明符 标识符,指明可以接受一个由“类型说明符”所规定类型的常量作为参数。
“模板参数表”同时包含上述多项内容时,各项内容以逗号分隔。应该注意的是,模板类的成员函数必须是模板函数。

一个类模板声明自身不产生代码,他说明了类的一个家族。只有当它被其它代码引用时,模板才根据引用的需要产生代码。

使用一个模板类来建立对象时,应按如下形式声明:

模板<模板参数表> 对象名1,…,对象名n;

使用实例:

#include <QCoreApplication>
#include <QDebug> struct Student {
int id;
float gpa;
}; template <class T>
class Store{
public:
Store(void); T GetElem(void);
void PutElem(T x); private:
T item;
int haveValue;
}; template <class T>
Store<T>::Store(void)
: haveValue(0)
{
} template <class T>
T Store<T>::GetElem(void) {
if (haveValue == 0) {
qDebug() << "No item present!";
exit(1);
}
return item;
} template <class T>
void Store<T>::PutElem(T x){
haveValue++;
item = x;
} int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv); Student g ={1000,23}; Store<int> S1,S2;
Store<Student> S3;
Store<double> D; S1.PutElem(3);
S2.PutElem(-7); qDebug() << S1.GetElem() << " " << S2.GetElem(); S3.PutElem(g); qDebug() << "The student id is "<< S3.GetElem().id;
qDebug() << "Retrieving object D ";
qDebug() << D.GetElem(); return a.exec();
}

输出结果:

输出结果

注意:本文中代码均使用 Qt 开发编译环境,如有疑问和建议欢迎随时留言。

作者:赵者也
链接:http://www.jianshu.com/p/4c64d1b567a7
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

https://www.cnblogs.com/aademeng/articles/7265011.html

C++ 函数模板与类模板(使用 Qt 开发编译环境)的更多相关文章

  1. [Reprint] C++函数模板与类模板实例解析

    这篇文章主要介绍了C++函数模板与类模板,需要的朋友可以参考下   本文针对C++函数模板与类模板进行了较为详尽的实例解析,有助于帮助读者加深对C++函数模板与类模板的理解.具体内容如下: 泛型编程( ...

  2. C++_进阶之函数模板_类模板

     C++_进阶之函数模板_类模板 第一部分 前言 c++提供了函数模板(function template.)所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来 ...

  3. C++复习:函数模板和类模板

    前言 C++提供了函数模板(function template).所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表.这个通用函数就称为函数模板.凡是函数体 ...

  4. 【校招面试 之 C/C++】第2题 函数模板、类模板、特化、偏特化

    1.C++模板 说到C++模板特化与偏特化,就不得不简要的先说说C++中的模板.我们都知道,强类型的程序设计迫使我们为逻辑结构相同而具体数据类型不同的对象编写模式一致的代码,而无法抽取其中的共性,这样 ...

  5. C++解析(26):函数模板与类模板

    0.目录 1.函数模板 1.1 函数模板与泛型编程 1.2 多参数函数模板 1.3 函数重载遇上函数模板 2.类模板 2.1 类模板 2.2 多参数类模板与特化 2.3 特化的深度分析 3.小结 1. ...

  6. C++学习之函数模板与类模板

    泛型编程(Generic Programming)是一种编程范式,通过将类型参数化来实现在同一份代码上操作多种数据类型,泛型是一般化并可重复使用的意思.泛型编程最初诞生于C++中,目的是为了实现C++ ...

  7. C++ 模板常见特性(函数模板、类模板)

    背景 C++ 是很强大,有各种特性来提高代码的可重用性,有助于减少开发的代码量和工作量. C++ 提高代码的可重用性主要有两方面: 继承 模板 继承的特性我已在前面篇章写过了,本篇主要是说明「模板」的 ...

  8. C++进阶-1-模板基础(函数模板、类模板)

    C++进阶 模板 1.1 函数模板 1 #include<iostream> 2 using namespace std; 3 4 // 模板 5 6 // 模板的简单实例 7 // 要求 ...

  9. 学习C++模板,类模板

    当我们使用向量时,会经常使用形如:vector<int> a的式子.这个表达式就是一个类模板实例化的例子,vector是一个类模板,我们给他传递模板参数(见<>里),然后创建一 ...

随机推荐

  1. 13Microsoft SQL Server SQL 高级事务,锁,游标,分区

    Microsoft SQL Server SQL高级事务,锁,游标,分区 通过采用事务和锁机制,解决了数据库系统的并发性问题. 9.1数据库事务 (1)BEGIN TRANSACTION语句定义事务的 ...

  2. 2019西安多校联训 Day1

    试题链接:http://www.accoders.com/contest.php?cid=1893  考试密码请私信;    T1 明明就是O(n)的模拟,强行打成二分QAQ 思路:判断收尾是否为1或 ...

  3. python3.x Day1 菜单程序练习

    三级菜单: 1. 运行程序输出第一级菜单 2. 选择一级菜单某项,输出二级菜单,同理输出三级菜单 3. 菜单数据保存在文件中 4. 让用户选择是否要退出 5. 有返回上一级菜单的功能 类定义:menu ...

  4. Codeforces Round #395 C. Timofey and a tree

    package codeforces; import java.util.*; public class CodeForces_764C_Timofey_and_a_tree { static fin ...

  5. [bzoj4300][绝世好题] (动规)

    Description 给定一个长度为n的数列ai,求ai的子序列bi的最长长度,满足bi&bi-1!=0(2<=i<=len). Input 输入文件共2行. 第一行包括一个整数 ...

  6. phpcms 短信替换

    后台表单向导文件路径: [/www/wwwroot/phpcms/phpcms/modules/formguide/templates/formguide_info_list.tpl.php] pub ...

  7. Eclipse 导出的jar包 , 使用后提示重复定义?

    导出jar包时,一般会指定一个路径,导出的完整jar包就会自动放到那个指定路径里. 后来我发现那个指定路径的jar包比bin文件夹里面的jar包大,于是就用bin文件夹里面的jar包代替来试试,果然不 ...

  8. codeforces 371c

    #include<stdio.h> int main() { char s[200]; __int64  r,nb,ns,nc,pb,ps,pc,i,sum,tob,tos,toc; wh ...

  9. [poj1704]Georgia and Bob_博弈论

    Georgia and Bob poj-1704 题目大意:题目链接 注释:略. 想法:我们从最后一个球开始,每两个凑成一对.如果有奇数个球,那就让第一个球和开始位置作为一对. 那么如果对手移动的是一 ...

  10. [bzoj 2705][SDOI2012]Longge的问题(数学)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2705 分析: 设k为n的因数 设f[k]为gcd(x,n)==k的x的个数,容易知道a ...