一,首先看看函数模板和类模板的区别:

1.声明方式不同,以sum(int a,int b)为例

//函数模板
template<tepename T>
const T&sum(const T&a,const T&b) const
{...return T();
}

然而类模板中的每个成员函数除了(友元)几乎都是函数模板,特别注意的是类模板的声明和定义往往都在 .h头文件中。

//类模板
#pragma once
template<class T>
class Pair
{private:...
public:Pair(){}const T&sum(const T&a,const T&b) const~Pair(){;}...
};template<class T>//头文件中定义,因为类模板主要是给编译器下达指令如何编译在生成特定的运行代码
template<T>::const T&sum(const T&a,const T&b) const
{...return T();
}

2,具体化的异同
他们都有隐式实例化(编译器根据模板自己推演),和具体化(显示实例化和具体化),其形式大体相似。

//函数模板的具体化
...
template<class T>
void Swap(T&,T&);//函数模板template<>void Swap(job&,job&);//显示具体化
int main()
{template void Swap<>(char&,char &);//or template void Swap<char>(char&,char &)//显示实例化,因为该实例化参数列表中可以推断出实例化的类型,所以可以不特定指出<>里面为char,如果没有参数列表必须指出实例化,<>里面的类型...int a,b;Swap(a,b);//调用隐式实例化...job n,m;Swap(n,m);//调用显示具体化;...char c,d;Swap(c,d);//调用显示具体化;//**
## 特别的你还可以自定义选择:Swap(T1,T2)<>;Swap(T1,T2)<int ,int>;//将模板中的T替换为int
}

实例化和具体化的区别第一点在于template后面的<>有和无,第二点在于具体化需要定义,而实例化只需要声明告诉编译器如何使用模板生成你指定的类型。

//类模板的具体化
//类的显示实例化
声明必须位于模板所在的名称空间内,然后根据通用模板生成特定的具体化
template class AraayTp<string,100>;
//类的显示具体化的格式
template<> class 类名<具体化的类型>{}
eg:
template<>class SortArray<const char* >
{...
};
表示提供一个专门const char *类型使用的SortArray模板

值的注意的是,类模板还支持部分具体化,也就是部分闲置模板的通用性

eg:
template <class T1,class T2> class Pair<T1,T2>{...};//一般模板的定义
template <class T1> class Pair<T1,int>{...};//部分具体化
template后的<>里面表示没有被具体化的参数,上述列子表示参数T1没被具体化,而参数T2被具体化为int
如果<>为空将导致具体化

类模板部分具体化的注意的问题:
1,如果有多个模板可以选择则选择具体化程度最高的模板

Pair<double,double>p1;//选择一般模板
Pair<double,int>p2//选择部分具体化模板

2,编译器优先选择含有指针类型具体化,普通版本优先程度低于指针版本

stack<char>st1;//#1
stack<char *>st2//#2

//#2含有指针类型,编译器优先选择#2

二,深入探讨类模板的特性:

1,成员模板和将模板作为参数

...
//相当于类的嵌套,iner模板作为basic模板的成员
template<class T>
class basic
{private:template<typename U>class iner{...};iner<T>q;iner<int>q2;public:basic(){}....
};

一个更恰当的例子,成员模板的实用:

//完整的代码可运行,实现了一个利用vector的特性实现一个队列
//其中vector模板作为Queue的成员
#pragma once
#include <vector>
#include <iostream>
#include <queue>
using namespace std;template<class T>
class QueueTp
{private:using arryTP = vector<T>;arryTP que;//vector模板作为成员queue<int>q;
public:QueueTp() {que = vector<T>();}int cuSize()const;bool isempty() { return que.empty(); }void push(const T&it);void pop(T&it);//弹出一个元素到it中T front()const;~QueueTp() {}};template<class T>
int QueueTp<T>::cuSize() const
{return que.size();
}template<class T>
void QueueTp<T>::push(const T & it)
{que.push_back(it);
}template<class T>
void QueueTp<T>::pop(T & it)
{//使用迭代器typename arryTP::iterator firstElement = que.begin();que.erase(firstElement);
}template<class T>
T QueueTp<T>::front() const
{return que.front();
}

2,类模板的还有一个特性是将模板作为参数(模板包含 本身就是模板 的参数)(全部文件在这,可粘贴测试):
//头文件

#pragma once
#include <iostream>
/*#include <stack>*/
#include "stackp.h"
#include <queue>
using namespace std;template<template<typename T>class  Thing>
class Crab
{private:Thing<int> s1;Thing<double>s2;public:Crab() {};//假定Thing有一个push()和pop()bool push(int a,double x){ return s1.push(a) && s2.push(x); }bool pop(int &a, double &x){  return s1.pop(a) && s2.pop(x); }~Crab(){;}
};

//主函数进行测试

#include "pch.h"
#include <iostream>
/*#include <stack>*/
#include "Crab.h"
#include "beta.h"
int main()
{Crab<stackp>neb;int a;double b;while (cin>>a>>b&&a>0&&b>0){if (!neb.push(a,b))break;}cout << "两个元素同时出栈后的结果:" << endl;while (neb.pop(a,b)){cout << a << " , " << b << endl;}return 0;
}

//stackp.h文件

#pragma once
#include <iostream>
using namespace std;
template<class Type>class stackp
{private:enum { SIZE = 10 };int stacksize;int top;int currentsize;Type *item;public:explicit stackp(int s=SIZE);stackp(const stackp&st);int cuSize()const;bool isfull() { return top == stacksize; }bool isempty() { return top == 0; }bool push(const Type&it);bool pop(Type&it);//弹出一个元素到it中Type Top()const;~stackp() { delete[]item; }
};template<class Type>
inline stackp<Type>::stackp(int s):stacksize(s), top(0)
{item = new Type[stacksize];currentsize = 0;
}template<class Type>
stackp<Type>::stackp(const stackp & st)
{stacksize = st.stacksize;currentsize = st.currentsize;top = st.top;item = new Type[stacksize];for (int i=0;i<stacksize;i++){item[i] = st.item[i];}
}template<class Type>
inline int stackp<Type>::cuSize() const
{return currentsize;
}template<class Type>
inline bool stackp<Type>::push(const Type & it)
{if (top<stacksize){item[top++] = it;currentsize++;return true;}return false;
}template<class Type>
inline bool stackp<Type>::pop(Type & it)
{if (top>0){it = item[--top];currentsize--;return true;}return false;}template<class Type>
inline Type stackp<Type>::Top() const
{if (top-1>=0){return item[top - 1];}cout << "错误" << endl;exit(-1);}

2,类模板和友元

1.非模板友元

...
class HasFriend
{private:static int ct;...public:             **//1 声明**friend void counts();//不含有模板参数friend void reports(HasFriend<T>&);//含模板参数()里面必须指出具体化,而不是HasFriend&...
}void counts()
{cout<<"int count"<<HasFriend<int>::ct<<endl;
cout<<"int count"<<HasFriend<double>::ct<<endl;
}**//2定义**参数类型必须声明特定类型具体化
void reports(HasFriend<int>&a)
{...
}void reports(HasFriend<double>&a)
{...
}

非模板友元report()本身并不是模板函数,只是使用了一个模板参数,所以定义中必须使用显示具体化其具体类型

2,约束模板友元函数(一个三部曲的每种T类型都有自己的友元函数)

第一步:在类定义的前面声明每个模板函数

template void counts();
template void reports(T
&);//外部声明

第二步:类中声明友元并根据类模板参数的类型声明具体化

friend void counts();
friend void reports<>(HasFriend
&);

第三步:根据第一步的声明提供定义

template<typename TT》
inline void counts()
{
cout << "tempalte size: "
<< sizeof(HasFriend<TT》) << ": " << "template cunts: " <<
HasFriend<TT》::ct << endl;
}

友元不属于类所以模板声明是template中的参数可以自定义比如上面是TT,只要保证定义里面的参数是对应的即可(使用中文》是因为与博客的引用>发生冲突)

template<class T》
inline void reports(T &hf)
{
cout << hf.item <<
endl;
}

eg:
#pragma once
#include<iostream>
using namespace std;template<typename T> void counts();
template<class T> void reports(T &);//外部声明template<typename TT>
class HasFriend
{private:TT item;static int ct;
public:friend void counts<TT>();friend void reports<>(HasFriend<TT>&);HasFriend(const TT&i):item(i){ct++;}~HasFriend(){ct--;}
};template<typename T>
int HasFriend<T>::ct = 0;template<typename T>
inline void counts()
{cout << "tempalte size: " << sizeof(HasFriend<T>) << ":  " << "template cunts: " << HasFriend<T>::ct << endl;
}template<class T>
inline void reports(T &hf)
{cout << hf.item << endl;
}
int main()
{counts<int>();//是一个约束模板友元必须具体化HasFriend<int>hfi1(10);HasFriend<int>hfi2(20);HasFriend<double>hfdb(10.5);reports(hfi1);reports(hfi2);reports(hfdb);cout << "count<int>的输出:" << endl;counts<int>();cout << "count<double>的输出:" << endl;counts<double>();return 0;
}

//输出:——————————————————————————————————————————
tempalte size: 4: template cunts: 0
10
20
10.5
count的输出:
tempalte size: 4: template cunts: 2
count的输出:
tempalte size: 8: template cunts: 1
E:\c++语法xuxi\c++重构\Debug\类模板-成员模板和友元.exe (进程 13896)已退出,返回代码为: 0。
若要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口…

**

注意:

**

正如标题所说每一T类型都有各自的友元函数counts()相互独立

3,模板类的非约束模板友元函数(友元模板类型参数和类模板参数不同的友元)

声明:
template<typename T>]
class xx
{private:T xxx;...template<class C,class D> friend void show(C&,D&);
}定义:
template<class C,class D> friend void show(C&c,D&d)
{cout<<c.xxx<<d.xxx;
}

假如在main中声明对象 xxhf(10); 则编译器工作时用xx替换C,D friend void
show(xx&,xx&);

模板(上)完!

一文解决函数模板和类模板(上)相关推荐

  1. 判断exception类型_C++核心准则T.44:使用函数模板推断类模板参数类型(如果可能)...

    T.44: Use function templates to deduce class template argument types (where feasible) T.44:使用函数模板推断类 ...

  2. 函数模板和类模板的使用

    函数模板 //交换 int 变量的值 void Swap(int *a, int *b){ int temp = *a; *a = *b; *b = temp; } //交换 float 变量的值 v ...

  3. C++基础:模板,函数模板和类模板

    文章目录 1. 函数模板 2. 类模板 3. 模板特化 3.1 函数模板特化 3.2 类模板特化 4. 非类型模板参数 模板是允许函数或类通过泛性的形式表现或运行的特性 1. 函数模板 模板可以使函数 ...

  4. 函数模板和类模板详解

    C++ 中的模板主要是函数模板和类模板 大致可以分为:模板函数 和模板类 其中模板类主要解决对象问题  . 第一部分:函数模板 1.在 C++ 中为了操作简洁我们引入了函数模板.所谓的函数模板实际上是 ...

  5. 笔记②:牛客校招冲刺集训营---C++工程师(面向对象(友元、运算符重载、继承、多态) -- 内存管理 -- 名称空间、模板(类模板/函数模板) -- STL)

    0618 C++工程师 第5章 高频考点与真题精讲 5.1 指针 & 5.2 函数 5.3 面向对象(和5.4.5.5共三次直播课) 5.3.1 - 5.3.11 5.3.12-14 友元 友 ...

  6. 泛型编程之函数模板和类模板

    1. 函数模板 C++一种编程思想称为泛型编程,主要利用的技术就是模板 C++提供两种模板机制:函数模板和类模板.这里介绍函数模板,类模板在该专题下的另外篇文章中. 函数模板作用:建立一个通用函数,其 ...

  7. C++模板学习02(类模板)(类模板语法、类模板与函数模板的区别、类模板中的成员函数创建时机、类模板对象做函数参数、类模板与继承、类模板成员函数类外实现、类模板分文件编写、类模板与友元)

    C++引用详情(引用的基本语法,注意事项,做函数的参数以及引用的本质,常量引用) 函数高级C++(函数的默认参数,函数的占位参数,函数重载的基本语法以及注意事项) C++类和对象-封装(属性和行为作为 ...

  8. C++笔记7:C++提高编程1:模板—[函数模板和类模板]

    0820 C++提高编程: 1.模板-[函数模板和类模板] 2.初识STL 3.STL-常用容器 4.STL-函数对象 5.STL-常用算法 C++提高编程引言: C++除了面向对象编程思想,还有泛型 ...

  9. 模板详解 --- 函数模板与类模板

    目录 函数模板 函数模板的格式: 函数模板的实例化: 模板参数的匹配原则 类模板 类模板的格式: 类模板的实例化: 非类型模板参数 我们为什么要使用模板?         C++使用模板的目的是为了解 ...

最新文章

  1. (C++)一行代码递归实现辗转相除法
  2. 嵌入式系统linux之光标隐藏解决
  3. git commit -amend_最常见的Git错误都有哪些,如何解决它们?
  4. 计算机审计中级培训结业考试,第二期计算机审计中级培训班结业考.doc
  5. 小孩都看得懂的YOLO!
  6. php smarty入门,smarty 快速入门
  7. css中em与px的介绍及换算方法
  8. 根据当前docker容器生成镜像提交到远端服务器
  9. Java文档阅读笔记-Guide to the Hibernate EntityManager
  10. 失败的信息化案例分享
  11. java switch的应用
  12. 雨棚板弹性法计算简图_钢结构雨篷图纸计算书
  13. 小游戏打包发布安卓APK
  14. 论机电一体化的发展By integration of machinery development
  15. Win 10 忘记密码不用U盘就可解决
  16. APP逆向分析之XX音乐客户端下载歌曲权限绕过
  17. springboot依赖lombok插件、lombok常用注解
  18. 【操作系统实验】实验二 进程管理
  19. [转]Visual C++ 和 C++ 有什么区别?
  20. APP推广之APP内容营销十大经典案例

热门文章

  1. html实现图片在立体,css3实现图片立体化缩放
  2. android studio如何画图,关于Android studio基础画图用法
  3. 17下列命令中_哪个命令是java的编译命令?,下列命令中,哪个命令是Java的编译命令?A.java cB.javaC.java docD.applet viewer...
  4. 小程序项目:基于微信小程序的在线考试系统springboot框架——计算机毕业设计
  5. 如何让电脑文件夹同步手机
  6. GlusterFS分布式文件系统群集
  7. Linux命令详解:tail - 实时查看文件内容
  8. JQuery图片轮换器原理
  9. 移动端-确认订单页面
  10. 在三四线小城市投资3至8万,做什么小生意好?