目录
一:模板函数
1.1 一般模板函数
模板(Template)指C++程序设计设计语言中采用类型作为参数的程序设计,支持通用程序设计。使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。下面来看一个简单的例子
#include<iostream>
using namespace std;
template<typename T>
int compare(const T&v1, const T& v2)
{
if (v1 > v2) {
return 1;
}
if (v1 < v2) {
return -1;
}
else {
return 0;
}
}
int main()
{
const char* cp1 = "world", * cp2 = "hi";
int i1 = 1, i2 = 2;
int a,b;
a=compare(i1, i2);
b=compare(cp1, cp2);
cout << a << endl;
cout << b << endl;
}
上面的一个例子即为一般模板的形式,对于不同的两种类型数值可以调用同一个函数。其中template和typename是关键字,typename可以用class 关键字代替,在这里typename 和class没区别,<>括号中的参数叫模板形参,模板形参和函数形参很相像,模板形参不能为空。
1.2特化模板函数
函数模板特化是在一个统一的函数模板不能在所有类型实例下正常工作时,需要定义类型参数在实例化为特定类型时函数模板的特定实现版本。查看如下例子。
#include <iostream>
using namespace std;
template<typename T>
T Max(T t1, T t2) {
return (t1 > t2) ? t1 : t2;
}
typedef const char* CCP;
template<>
CCP Max(CCP s1, CCP s2) { //使用函数重载实现函数模板特化的功能
return (strcmp(s1, s2) > 0) ? s1 : s2;
}
int main() {
//调用实例:int Max<int>(int,int)
int i = Max(10, 5);
//调用显示特化:const char* Max<const char*>(const char*,const char*)
const char* p = Max("week", "good");
cout << "i:" << i << endl;
cout << "p:" << p << endl;
}
如果不给出函数模板Max<T>在T为const char*时的特化版本,那么在比较两个字符串的大小时,比较的是字符串的起始地址的大小,而不是字符串的内容在字典序中先后次序。结果展示
二:模板类
2.1模板类
模板类是指建立一个通用类,其数据成员、成员函数的返回值类型和形参类型不具体指定,用一个虚拟的类型来代表。使用模板类定义对象时,系统会实参的类型来取代类模板中虚拟类型从而实现了不同类的功能。下面我们来看一个比较两个元素大小的模板类测试
#include<iostream>
using namespace std;
template<typename T>
class compare
{
public:
T x, y;
compare(T a, T b) {
x = a;
y = b;
}
T max()
{
return (x > y) ? x : y;
}
};
int main()
{
compare<int>com1(3, 7);
cout << com1.max() << endl;
compare<double>com2(12.34, 56.78);
cout << com2.max() << endl;
compare<char>com3('a', 'x');
cout << com3.max() << endl;
}
结果展示:
本例中创建了compare模板类,并声明了三个类型分别为int,double,char的变量,全部调用类里面的函数,这就是模板类的基本使用
2.2成员模板函数
在类的成员里面也可以创建模板,下面看一个简单例子
#include <iostream>
using namespace std;
class A
{
public:
template<typename T>
void compare(const T& v1, const T& v2)
{
if (v1 > v2) {
cout << v1 << endl;
}
else {
cout << v2 << endl;
}
}
};
int main()
{
A a;
a.compare(4, 6);
a.compare("week", "good");
a.compare(5.5, 6.5);
结果展示:
可以看到在类的里面定义的模板依旧可以使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。
2.3 模板特化
2.3.1模板成员函数特化
模板成员函数特化与模板函数特化大致相同,只不过一个是在类里面定义,使用时要先声明一个类变量,我们可以把前面模板函数特化稍加修改来完成一个简单的测试
#include <iostream>
using namespace std;
class A
{
public:
template<typename T>
T Max(T t1, T t2) {
return (t1 > t2) ? t1 : t2;
}
typedef const char* CCP;
template<>
CCP Max(CCP s1, CCP s2) {
return (strcmp(s1, s2) > 0) ? s1 : s2;
}
};
int main() {
A a;
cout << a.Max(10, 5) << endl;
cout << a.Max("week", "good") << endl;
}
结果展示:
同样的,如果不给出函数模板Max<T>在T为const char*时的特化版本,那么在比较两个字符串的大小时,比较的是字符串的起始地址的大小,而不是字符串的内容在字典序中先后次序。
2.3.2模板类特化
类模板特化类似于函数模板的特化,即类模板参数在某种特定类型下的具体实现。模板的特化基本上是相同的,下面看一个例子
#include <iostream>
using namespace std;
template<typename T>
class A {
T num;
public:
A() {
num = T(6.6);
}
void print() {
cout << "num:" << num << endl;
}
};
template<>class A<char*> {
const char* str;
public:
A() {
str = "A special definition ";
}
void print() {
cout << str << endl;
}
};
int main() {
A<int> a1; //显示模板实参的隐式实例化
a1.print();
A<char*> a2;//使用特化的类模板
a2.print();
}
结果展示:
三:模板类AutoPtr
由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 delete。但是 new 完之后做了一些事情,到最后旧经常会忘记delete。因此提供了一种引用计数机制实现的智能指针模板类。实现原理是在构造的时候获取资源,在析构的时候释放资源,并进行相关指针操作的重载。如下所示
在这里需要注意:
1.无论何时一个引用被销毁或者重写,它所引用的对象的引用计数都会减少。
2.无论何时一个引用被创建或者被拷贝,它的引用的对象的引用计数都会增加。
3.初始时的引用计数是 1。
4.当一个对象的引用为 0 时,这个对象资源被销毁。
5.在多线程情况下增加和减少必须是原子操作。
对象拥有权:
1.任何对象都可能拥有一个或多个所有者。
2.只要一个对象至少还拥有一个所有者,它就会继续存在。
3.如果一个对象没有所有者,那么可以被销毁。
下面来看一下核心代码的实现
智能指针构造函数的实现如下:
template < class T>
AutoPtr<T>::AutoPtr(T * pData)
{
m_pData = pData;
m_nUser = new int(1); //初始化值为1
}
析构函数的实现:
template < class T>
void AutoPtr<T>::decrUser()
{
‐‐(*m_nUser);
if ((*m_nUser) == 0) {
delete m_pData;
m_pData = 0;
delete m_nUser;
m_nUser = 0;
}
}
template < class T>
AutoPtr<T>::~AutoPtr()
{
decr()
}
等号的重载
template < class T>
AutoPtr<T>&AutoPtr<T>::operator=(const AutoPtr<T>&h)
{
decrUser();
m_pData = h.m_pData;
m_nUser = h.m_nUser;
*m_nUser)++;
}
->和*的重载
T* operator‐> ()
{
return m_pData;
}
T& operator*()
{
return *m_pData;
}