如果一个类的成员变量的类型、成员函数返回值、参数表、局部变量的类型、类的成员类型甚至基类的类型,用参数表示,那么这个类就是一个类模板。
1.定义
template<typename 类型形参1,typename 类型形参2, ...>
class 类模板名 [: 继承表] {
成员变量
成员函数
成员类型
};
在成员变量、成员函数、成员类型,以及继承表中都可以引用类型形参。
例如:
template<typename M, typename R, typename A,
tyepname V, typename T, typename B>
class MyClass : public B {
M m_mem;
R fun (A arg) { ... V var ... }
typedef T* pointer;
};
2.使用
类模板名<类型实参1,类型实参2,...> 对象(构造实参表);
类模板名<类型实参1,类型实参2,...>& 引用 = 对象;
类模板名<类型实参1,类型实参2,...>* 指针 = &对象;
|<---------------------------->|
类
用类模板创建对象实际上包含了两个实例化过程:
编译期 运行期
类模板 -实例化-> 类 -实例化-> 对象
编译器 处理器
任何时候一个类模板都不具备类型语义:
A.类模板不能被放在"::"运算符前面;
B.类模板不能作为sizeof/typeid运算符的运算数;
...
只有的当该类模板结合了类型实参,即被实例化为具体类以后才具有类型语义。
注意:类模板的类型参数不能隐式推断,必须显式指明。
3.类型参数
1)类模板中,只有那些被调用的成员函数才会被实例化,即产生实例化代码。某些类型虽然并没有提供类模板所要求的全部功能,但照样可以实例化该类模板,只要不直接或间接调用那些依赖于未提供功能的成员函数即可。
2)作为类模板的设计者,应该尽量减少对类型实参的要求,以降低类模板使用者的工作量。
#include <iostream> using namespace std; template<typename T> class Comparator { public: Comparator (T x, T y) : m_x (x), m_y (y) {} T max (void) const { return m_x < m_y ? m_y : m_x; } T min (void) const { return m_x < m_y ? m_x : m_y; } private: T m_x, m_y; }; class Integer { public: Integer (int arg) : m_var (arg) {} friend ostream& operator<< ( ostream& os, Integer const& i) { return os << i.m_var; } //自定义比较函数 bool operator< ( Integer const& i) const { return m_var < i.m_var; } /* bool operator> ( Integer const& i) const { return m_var > i.m_var; } */ private: int m_var; }; int main (void) { int a = 123, b = 456; Comparator<int> ci (a, b); cout << ci.max () << ' ' << ci.min () << endl; double c = 1.3, d = 4.6; Comparator<double> cd (c, d); cout << cd.max () << ' ' << cd.min () << endl; string e = "hello", f = "world"; Comparator<string> cs (e, f); cout << cs.max () << ' ' << cs.min () << endl; Comparator<Integer> cn (a, b); cout << cn.max () << ' ' << cn.min () << endl; return 0; }
4.静态成员变量
类模板的静态成员变量,既不是一个对象一份,也不是一个模板一份,而是在该类模板的每个实例化类中各有一份,且为该实例化类的所有对象所共享。
#include <iostream> using namespace std; template<typename T> class A { public: void foo (void) const { cout << "this: " << this << ", &m_var: " << &m_var << ", &s_var: " << &s_var << endl; } private: int m_var; static int s_var; }; template<typename T> int A<T>::s_var; int main (void) { static A<int> a, b; static A<double> c, d; a.foo (); b.foo (); c.foo (); d.foo (); }
5.递归实例化
-------------------------------------------------
int a = 10;
int b;
b = a;
---------------------------
int a[5] = {1, 2, 3, 4, 5};
int b[5];
b = a; // 错误,数组不能只有直接赋值
---------------------------
struct Array {
int a[5];
};
...
Array a = {1, 2, 3, 4, 5}
Array b = a;
-------------------------------------------------
用一个类模板的实例化类型实例化该类模板自身的实例化方式被称为类模板的递归实例化。通常用这种方法可以很方便地构建那些在空间上具有递归特性的数据结构,如:多维数组、二叉树等。
注意:模板参数表的右尖括号一定不能紧挨着,期间至少要保留一个空格,以防止编译器将其误解为右移运算符。
#include <iostream> using namespace std; template<typename T = int, size_t S = 3> class Array { public: T& operator[] (size_t i) { return m_a[i]; } T const& operator[] (size_t i) const { return const_cast<Array&> (*this)[i]; } size_t size (void) const { return sizeof (m_a) / sizeof (m_a[0]); } private: T m_a[S]; }; //访问的都是共有成员,可以放在外面 template<typename T> ostream& operator<< (ostream& os,Array<T> const& arr) { size_t size = arr.size (); for (size_t i = 0; i < size; ++i) os << '(' << arr[i]/*++*/ << ')'; return os; } int main (void) { Array<int> a; a[0] = 10; // a.operator[](0) = 10; a[1] = 20; a[2] = 30; cout << a << endl; Array<int> b = a; // 拷贝构造 cout << b << endl; Array<int> c; c = b; // 拷贝赋值 cout << c << endl; Array<string> d; d[0] = "北京"; d[1] = "上海"; d[2] = "广州"; cout << d << endl; Array<Array<int> > e; for (int i = 0; i < e.size (); ++i) for (int j = 0; j < e[i].size ();++j) e[i][j] = (i+1)*10+j+1; cout << e << endl; Array<Array<Array<int> > > f; int const /*volatile*/ col = 4; Array<Array<int, col>, 1+1+1> g; for (int i = 0; i < g.size (); ++i) for (int j = 0; j < g[i].size ();++j) g[i][j] = (i+1)*10+j+1; for (int i = 0; i < g.size (); ++i) { for (int j = 0; j < g[i].size ();++j) cout << g[i][j] << ' '; cout << endl; } return 0; }
扩展用法
template<typename T> class Array; // 数组
template<typename T> class List; // 链表
Array<Array<int> > a; // 二维数组
List<List<int> > b; // 二维链表
Array<List<int> > c; // 链表数组
List<Array<int> > d; // 数组链表
template<typename T> class BiTree; // 二叉树
BiTree<List<Array<int> > > e;
6.特(例)化
如果一个类模板的通用实现针对某些特殊的类型实参,不能做出正确的处理,或者处理虽然可行但性能不佳,那么就可以针对该类型实参给出特殊的实现,以弥补通用版本的不足,这就叫类模板的特(例)化。
1)全类(模板)特化
template<>
class 类模板名<类型实参1, 类型实参2, ...> { ... };
2)成员特化
template<>
返回类型 类模板名<类型实参1,类型实参2, ...>::成员函数名 (调用实参表) { ... }
注意,类模板的特化只是一种权宜之计,不应成为损失通用设计的借口。
#include <cstring> #include <iostream> using namespace std; // 通用版本 template<typename T> T max (T x, T y) { return x < y ? y : x; } // 针对char*类型的重载版本 char* max (char* x, char* y) { return strcmp (x, y) < 0 ? y : x; } // 通用版本 template<typename T> class Comparator { public: Comparator (T x, T y) : m_x (x), m_y (y) {} T max (void) const { return m_x < m_y ? m_y : m_x; } /* char* max (void) const { return strcmp (m_x, m_y) < 0 ? m_y : m_x; } */ private: T m_x, m_y; }; // 针对char*类型的特化版本 /* template<> class Comparator<char*> { public: Comparator (char* x, char* y) : m_x (x), m_y (y) {} char* max (void) const { return strcmp (m_x, m_y) < 0 ? m_y : m_x; } private: char* m_x, *m_y; }; */ template<> char* Comparator<char*>::max (void) const { return strcmp (m_x, m_y) < 0 ? m_y : m_x; } int main (void) { int a = 123, b = 345; cout << ::max (a, b) << endl; char c[] = "hello", d[] = "world"; // cout << ::max (c, d) << endl; // cout << ::max (string (c), // string (d)) << endl; // cout << ::max<string> (c, d) << endl; cout << ::max (c, d) << endl; Comparator<int> ci (a, b); cout << ci.max () << endl; Comparator<char*> cs (c, d); cout << cs.max () << endl; return 0; }
7.局部(偏)特(例)化
1)只针对通用版本中的部分类型参数所做的特化被称为类模板的局部特化或偏特化。
2)类模板的局部特化只能以全类方式进行,不能只针对成员函数做特化。
3)虽然没有强调类型参数取某种特定类型,但是强调类型参数之间的某种特殊关系或特殊属性,这种情况也属于局部特化。
#include <iostream> #include <typeinfo> using namespace std; // 通用版本 template<typename A, typename B> class X { public: static void foo (void) { cout << "X<A,B>" << endl; } }; // 完全特化 template<> class X<int, short> { public: static void foo (void) { cout << "X<int,short>" << endl; } }; // 局部特化 template<typename A> class X<A, short> { public: static void foo (void) { cout << "X<A,short>" << endl; } }; template<typename A> class X<A, A> { public: static void foo (void) { cout << "X<A,A>" << endl; } }; template<typename A> class X<A, A*> { public: static void foo (void) { cout << "X<A,A*>" << endl; } }; template<typename A, typename B> class X<A*, B*> { public: static void foo (void) { cout << "X<A*,B*>" << endl; cout << typeid (A).name () << ' ' << typeid (B).name () <<endl; } }; template<typename A> class X<A*, A*> { public: static void foo (void) { cout << "X<A*,A*>" << endl; } }; int main (void) { X<int, double>::foo (); X<int, short>::foo (); X<double, short>::foo (); X<int, int>::foo (); X<double, double*>::foo (); X<char***, int*****>::foo (); X<double*, double*>::foo (); return 0; }
int i;
int* p = &i;
int* q = p;
8.智能指针
1)利用栈对象析构过程销毁堆对象;
2)利用类模板做到类型无关;
3)利用操作符重载模拟平凡指针的行为;
4)利用转移拷贝避免double free异常;
5)利用局部特化管理动态分配的对象数组。
include <cstdio> #include <iostream> #include <memory> using namespace std; class A { public: A (int data = 0) : m_data (data) { cout << "A构造:" << this <<endl; } ~A (void) { cout << "A析构:" << this <<endl; } void foo (void) const { cout << m_data << endl; } int m_data; }; template<typename T> class AutoPtr { public: AutoPtr (T* p = NULL) : m_p (p) {} AutoPtr (AutoPtr& that) :m_p (that.release ()) {} AutoPtr& operator= (AutoPtr& that) { if (&that != this) reset (that.release ()); return *this; } ~AutoPtr (void) { delete m_p; } //返回对象本身用&,不是拷贝 T& operator* (void) const { return *m_p;//m_p是指针,加上*,返回对象本身,即A } //*this返回调用对象本身,**this复用上面的*函数,&取地址 T* operator-> (void) const { return &**this; } private: T* release (void) { T* p = m_p; m_p = NULL; return p; } void reset (T* p) { if (p != m_p) { delete m_p; m_p = p; } } T* m_p; }; template<typename T> class AutoPtr<T[]> { public: AutoPtr (T* p = NULL) : m_p (p) {} AutoPtr (AutoPtr& that) : m_p (that.release ()) {} AutoPtr& operator= (AutoPtr& that) { if (&that != this) reset (that.release ()); return *this; } ~AutoPtr (void) { delete[] m_p; } T& operator* (void) const { return *m_p; } T* operator-> (void) const { return &**this; } private: T* release (void) { T* p = m_p; m_p = NULL; return p; } void reset (T* p) { if (p != m_p) { delete[] m_p; m_p = p; } } T* m_p; }; int foo (void) { // A* pa = new A; // pa->m_data = 1000; // (*pa).foo (); // auto_ptr<A> pa (new A); // smart_ptr<A> pa (new A); // C++11 AutoPtr<A> pa (new A); pa->m_data = 1000; // pa.operator->()->m_data = 1000; (*pa).foo (); // 1000 // pa.operator*().foo (); AutoPtr<A> pb = pa; // 拷贝构造 ++pb->m_data; (*pb).foo (); // 1001 AutoPtr<A> pc (new A (2000)); pb = pc; // 拷贝赋值 ++pb->m_data; (*pb).foo (); // 2001 // ... FILE* fp = fopen ("none", "r"); if (! fp) { perror ("fopen"); // delete pa; return -1; } // ... fclose (fp); // ... // delete pa; return 0; } int main (void) { foo (); // auto_ptr<A> pa (new A[3]); AutoPtr<A[]> pa (new A[3]); return 0; }