介绍
如果你是个模板的高手,你就可以将ATL的学习作为一种享受。在这一节中,我将要尝试解释一些ATL使用的模板技术。我不能保证你读完本节后能成为一个模板高手,只能是尽我所能让你在读完本文后能够更轻松地理解ATL的源码。
程序35.
#include <iostream> using namespace std;
template <typename T> T Maximum(const T& a, const T& b) { return a > b a : b; } int main() { cout << Maximum(5, 10) << endl; cout << Maximum(''A'', ''B'') << endl; return 0; } |
程序的输出为:
在这里,由于模板函数的关系,我们就没有必要分别重载int和char数据类型的函数版本了。其中很重要的一点是,函数的两个参数类型必须一致。但是如果我们传入了不同的数据类型,我们就需要告知编译器应该把这个参数考虑为哪种数据类型。
程序36.
#include <iostream> using namespace std;
template <typename T> T Maximum(const T& a, const T& b) { return a > b a : b; }
int main() { cout << Maximum<int>(5, ''B'') << endl; cout << Maximum<char>(5, ''B'') << endl; return 0; } |
程序的输出为:
我们也可以编写类模板,下面就是一个简单版本的堆栈类模板。
程序37.
#include <iostream> using namespace std;
template <typename T> class Stack { private: T* m_pData; int m_iTop;
public: Stack(int p_iSize = 0) : m_iTop(0) { m_pData = new T[p_iSize]; }
void Push(T p_iData) { m_pData[m_iTop++] = p_iData; }
T Pop() { return m_pData[--m_iTop]; }
T Top() { return m_pData[m_iTop]; }
~Stack() { if (m_pData) { delete [] m_pData; } }
private: Stack(const Stack<T>&); Stack<T>& operator = (const Stack<T>&); };
int main() { Stack<int> a(10);
a.Push(10); a.Push(20); a.Push(30);
cout << a.Pop() << endl; cout << a.Pop() << endl; cout << a.Pop() << endl;
return 0; } |
这个程序中没有任何错误检验,不过这个程序的目的只是示范模板的用法,而不是真的要写一个专业的堆栈类。
程序的输出为:
我们也可以将数据类型作为一个模板参数来传递,并且为它设置一个默认值。让我们来稍微修改一下程序37(译注:原文为“程序36”,应为37),并将堆栈的尺寸作为一个模板参数来传递,而不是作为构造函数的参数。
程序38.
#include <iostream> using namespace std;
template <typename T, int iSize = 10> class Stack { private: T m_pData[iSize]; int m_iTop;
public: Stack() : m_iTop(0) {}
void Push(T p_iData) { m_pData[m_iTop++] = p_iData; }
T Pop() { return m_pData[--m_iTop]; } T Top() { return m_pData[m_iTop]; }
private: Stack(const Stack<T>&); Stack<T>& operator = (const Stack<T>&); };
int main() { Stack<int, 10> a;
a.Push(10); a.Push(20); a.Push(30);
cout << a.Pop() << endl; cout << a.Pop() << endl; cout << a.Pop() << endl; return 0; } |
程序的输出和前一个相同。这个程序最重要的一点为: template <typename T, int iSize = 10>,现在就有一个问题:哪一个更好呢?通常,传递模板参数的办法是优于给构造函数传递参数的。为什么呢?因为在你将堆栈尺寸作为模板参数传递的时候,这个给定数据类型的数组就会被自动创建;而给构造函数传递参数则意味着构造函数会在运行时使用new或malloc一系列功能来分配内存。如果我们已经确定在创建好堆栈之后就不再更改它的尺寸(就像上面程序中private段中拷贝构造函数和赋值运算符中的那样)了,那么无疑使用模板参数是更加适合的。
(译注:作者Amjad在上面两个程序中并未实现拷贝构造函数和赋值运算符,这大概是由于这两者对于本文的内容无关紧要之故吧。在此我要指出的是正如作者所说,“不是真的要写一个专业的堆栈类”、“没有任何错误检验”,并且这其中类的组织结构使得精确实现拷贝构造函数和赋值运算符有一定的难度,尤其是程序37——我们无法从一个已经定义好的堆栈获得它的最大容量。)
|