博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
类模板
阅读量:4978 次
发布时间:2019-06-12

本文共 8829 字,大约阅读时间需要 29 分钟。

如果一个类的成员变量的类型、成员函数返回值、参数表、局部变量的类型、类的成员类型甚至基类的类型,用参数表示,那么这个类就是一个类模板。
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 
using namespace std;template
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
ci (a, b);cout << ci.max () << ' ' << ci.min ()<< endl;double c = 1.3, d = 4.6;Comparator
cd (c, d);cout << cd.max () << ' ' << cd.min ()<< endl;string e = "hello", f = "world";Comparator
cs (e, f);cout << cs.max () << ' ' << cs.min ()<< endl;Comparator
cn (a, b);cout << cn.max () << ' ' << cn.min ()<< endl;return 0;}

 

4.静态成员变量
类模板的静态成员变量,既不是一个对象一份,也不是一个模板一份,而是在该类模板的每个实例化类中各有一份,且为该实例化类的所有对象所共享。

#include 
using namespace std;template
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
int A
::s_var;int main (void) {static A
a, b;static A
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 
using namespace std;template
class Array {public:T& operator[] (size_t i) {return m_a[i];}T const& operator[] (size_t i) const {return const_cast
(*this)[i];}size_t size (void) const {return sizeof (m_a) / sizeof (m_a[0]);}private:T m_a[S];};//访问的都是共有成员,可以放在外面template
ostream& operator<< (ostream& os,Array
const& arr) {size_t size = arr.size ();for (size_t i = 0; i < size; ++i)os << '(' << arr[i]/*++*/ << ')';return os;}int main (void) {Array
a;a[0] = 10;// a.operator[](0) = 10;a[1] = 20;a[2] = 30;cout << a << endl;Array
b = a; // 拷贝构造cout << b << endl;Array
c;c = b; // 拷贝赋值cout << c << endl;Array
d;d[0] = "北京";d[1] = "上海";d[2] = "广州";cout << d << endl;Array
> 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
> > f;int const /*volatile*/ col = 4;Array
, 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 
#include
using namespace std;// 通用版本template
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
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
{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
::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
(c, d) << endl;cout << ::max (c, d) << endl;Comparator
ci (a, b);cout << ci.max () << endl;Comparator
cs (c, d);cout << cs.max () << endl;return 0;}

 

7.局部(偏)特(例)化

1)只针对通用版本中的部分类型参数所做的特化被称为类模板的局部特化或偏特化。

2)类模板的局部特化只能以全类方式进行,不能只针对成员函数做特化。
3)虽然没有强调类型参数取某种特定类型,但是强调类型参数之间的某种特殊关系或特殊属性,这种情况也属于局部特化。

#include 
#include
using namespace std;// 通用版本template
class X {public:static void foo (void) {cout << "X
" << endl;}};// 完全特化template<>class X
{public:static void foo (void) {cout << "X
" << endl;}};// 局部特化template
class X
{public:static void foo (void) {cout << "X
" << endl;}};template
class X
{public:static void foo (void) {cout << "X
" << endl;}};template
class X
{public:static void foo (void) {cout << "X
" << endl;}};template
class X
{public:static void foo (void) {cout << "X
" << endl;cout << typeid (A).name () << ' '<< typeid (B).name () <
class X
{public:static void foo (void) {cout << "X
" << endl;}};int main (void) {X
::foo ();X
::foo ();X
::foo ();X
::foo ();X
::foo ();X
::foo ();X
::foo ();return 0;}

 

int i;

int* p = &i;
int* q = p;

8.智能指针

1)利用栈对象析构过程销毁堆对象;
2)利用类模板做到类型无关;
3)利用操作符重载模拟平凡指针的行为;
4)利用转移拷贝避免double free异常;
5)利用局部特化管理动态分配的对象数组。

include 
#include
#include
using namespace std;class A {public:A (int data = 0) : m_data (data) {cout << "A构造:" << this <
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
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;}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
pa (new A);// smart_ptr
pa (new A); // C++11AutoPtr
pa (new A);pa->m_data = 1000;// pa.operator->()->m_data = 1000;(*pa).foo (); // 1000// pa.operator*().foo ();AutoPtr
pb = pa; // 拷贝构造++pb->m_data;(*pb).foo (); // 1001AutoPtr
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
pa (new A[3]);AutoPtr
pa (new A[3]);return 0;}

 

转载于:https://www.cnblogs.com/LuckCoder/p/8668250.html

你可能感兴趣的文章
生成php所需要的APNS Service pem证书的步骤
查看>>
JavaWeb之JSON
查看>>
HOT SUMMER 每天都是不一样,积极的去感受生活 C#关闭IE相应的窗口 .
查看>>
optionMenu-普通菜单使用
查看>>
【MemSQL Start[c]UP 3.0 - Round 1 C】 Pie Rules
查看>>
Ognl中“%”、“#”、“$”详解
查看>>
我对应用软件——美团的看法
查看>>
struts2.x + Tiles2.x读取多个xml 配置文件
查看>>
表单校验之datatype
查看>>
python第六篇文件处理类型
查看>>
ubuntu16系统磁盘空间/dev/vda1占用满的问题
查看>>
grid网格布局
查看>>
JSP常用标签
查看>>
九涯的第一次
查看>>
处理器管理与进程调度
查看>>
向量非零元素个数_向量范数详解+代码实现
查看>>
java if 用法详解_Java编程中的条件判断之if语句的用法详解
查看>>
matlab sin函数 fft,matlab的fft函数的使用教程
查看>>
mysql adddate()函数
查看>>
mysql sin() 函数
查看>>