首页 > 代码库 > C++STL - 类模板

C++STL - 类模板

类的成员变量,成员函数,成员类型,以及基类中如果包含参数化的类型,那么该类就是一个类模板
 
1.定义
template<typename 类型形参1, typename 类型形参2,...>
class 类模板名[:基类]{
  成员变量
  成员函数
  成员类型
};
 
2.使用
类模板名<类型实参1,类型实参2,...> 对象;
类模板名<类型实参1,类型实参2,...> &引用 = 对象;
类模板名<类型实参1,类型实参2,...> *指针 = &对象;
注意: 类模板不能隐式推断,必须显示致命类型实参.
 
3.两步实例化
|<------编译期----->|  |<-----运行期----->|        
类模板 - 实例化 ----> 类 - 实例化 ----> 对象
    编译器      处理器
只有当调用成员函数的时候编译器才做类型检查
#include <iostream>
using namespace std;

template<typename T> class Comparator {
public:
    Comparator (T x, T y) :m_x (x), m_y (y) {}
    T min (void) const {return m_x < m_y ? m_x : m_y;}
    T max (void) const {return m_x < m_y ? m_y : m_x;}
    void foo (void) const {cout << "foo" << endl;}
private:
    T m_x, m_y;
};

class Integer {
public:
    Integer (int arg = 0) : m_var (arg) {}
    bool operator< (Integer const& rhs) const{
        return m_var < rhs.m_var;
    }
    friend ostream& operator<< (ostream& os,Integer const& i) {
        return os << i.m_var;
    }
private:
    int m_var;
};
int main (void) {
    int a = 123, b = 456;
    Comparator<int> ci (a, b);
    cout << ci.min () <<   << ci.max () << endl;
    double c = 1.3, d = 4.6;
    Comparator<double> cd (c, d);
    cout << cd.min () <<   << cd.max () << endl;
    string e = "hello", f = "world";
    Comparator<string> cs (e, f);
    cout << cs.min () <<   << cs.max () << endl;
    Comparator<Integer> cn (a, b);
    cout << cn.min () <<   << cn.max ()<< endl;
    return 0;
}
 
4.类型参数
(1)类模板中,所有的成员函数(无论其是否使用类型参数)都是函数模板, 都要延迟编译(即在编译看到调用该函数时编译),因此只有那些被调用的成员函数才会被实例化.
(2)某些类型虽然没有提供该类模板所需要的全部功能,但照样可以实例化该模板,只要不直接或间接调用那些依赖于为提供功能的成员函数即可.
 
5.类模板的静态成员变量
(1)非模板: 静态成员变量是类的一部分,一个类只有一份.
      普通成员变量是对象的一部分,每个对象都有一份
(2)类模板:静态成员变量既不是一个模板一份实例,也不是一个对象一份实例,而是在该类模板的每个实例化类中都有一份独立的实例,且为该实例化类所创建的每个对象所共享
#include <iostream>
using namespace std;
template<typename T> class A {
public:
    void paddr (void) const {
        cout << "非静:" << &m_var << ",静态:" << &s_var << endl;
    }
private:
    int m_var;
    static int s_var;
};
template<typename T> int A<T>::s_var;
int main (void) {
    A<int> a, b;
    A<double> c, d;
    a.paddr ();
    b.paddr ();
    c.paddr ();
    d.paddr ();
    return 0;
}

 

6.递归实例化
用一个类模板的实例化类型实例化该类模板自身
构建在空间上具有递归特征的复合结构,如:多维数组,二叉树等等
template<typename T> class Array{..};
template<typename T> class list{...};
template<typename T> class Tree{...};
 
Array<Array<int> > 二维数组
Array<List<int> >  链表数组
List<Array<int> >  数组链表
List<List<int> >   二维链表      ====>通过哈希值放姓名
Tree<List<Array<int> > > 数组链表树
 
7.特化/特例化
当一个类模板的通用实现无法满足某些特殊类型的需要,或者虽然可以满足需要,但是性能不佳,这时可以编写针对该特殊类型的特殊实现,这就叫类模板的特例化
(1)完全特化:针对全部类型参数所做的特化 ====>用的比较多
全类特化:用特定类型替换类型参数,把整个类模板重写一遍
成员特化:只重写类模板中部分与特化类型相关的成员函数
#include <iostream>
#include <cstring>
using namespace std;
// 通用版本
template<typename T> T max (T x, T y) {
    return x < y ? y : x;
}
// 针对字符指针类型的重载版本
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;
};
// 针对字符指针类型的特化版本
/*
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 = 456;
    cout << ::max (a, b) << endl;
    char c[] = "hello", d[] = "world";
    cout << ::max (c, d) << endl;
    /*
    cout << ::max<string> (c, d) << endl;
    cout << ::max (string (c), string (d)) << endl;
    */
    Comparator<int> ci (a, b);
    cout << ci.max () << endl;
    Comparator<char*> cs (c, d);
    cout << cs.max () << endl;
    return 0;
}
 
(2)局部特化(偏特化)
#include <iostream>
using namespace std;
// 通用版本
template<typename A, typename B> class X {
public:
    X (void) {cout << "X<A,B>" << endl;}
private:
    A m_a;
    B m_b;
};
// 完全特化
template<> class X<int, short> {
public:
    X (void) {cout << "X<int,short>" << endl;}
private:
    int m_a;
    short m_b;
};
// 局部特化
template<typename A> class X<A, short> {
public:
    X (void) {cout << "X<A,short>" << endl;}
private:
    A m_a;
    short m_b;
};
template<typename A> class X<A, A> {
public:
    X (void) {cout << "X<A,A>" << endl;}
private:
    A m_a;
    A m_b;
};
template<typename A> class X<A, A*> {
public:
    X (void) {cout << "X<A,A*>" << endl;}
private:
    A m_a;
    A* m_b;
};
template<typename A, typename B> class X<A*, B*> {
public:
    X (void) {cout << "X<A*,B*>" << endl;}
private:
    A* m_a;
    B* m_b;
};
template<typename A> class X<A*, A*> {
public:
    X (void) {cout << "X<A*,A*>" << endl;}
private:
    A* m_a;
    A* m_b;
};
int main (void) {
    // 选择顺序:完全特化>局部特化>通用版本
    X<int, short> x1;
    X<double, short> x2;
    X<char, short> x3;
    X<int, double> x4;
    X<int, int> x5;
    X<double, double> x6;
    X<int, int*> x7;
    X<double, double*> x8;
    X<int*, double*> x9;
    X<short**, char*****> x10;
    X<int*, int*> x11;
    return 0;
}

 

8.智能指针
(1)利用局部对象的析构函数销毁对象
(2)通过操作符重载用智能指针来模拟平凡指针的用法
(3)通过类型参数繁星花所维护的堆对象
(4)通过转移语义避免浅拷贝和深拷贝的矛盾
(5)通过局部特化来区分单个对象个对象数组 ==>>两种的释放方式不同
c++11一般不推荐使用auto_ptr, 而是代之以smart_ptr,这才是真正的智能指针.
智能指针的实现:
#include <errno.h>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <memory>
using namespace std;
class A {
public:
    A (void) {cout << "A构造:" << this << "->" << sizeof (*this) << endl;}
    ~A (void) {cout << "A析构:" << this << "->" << sizeof (*this) << endl;}
    void print (size_t i) const {cout << m_data[i] << endl;}
    int m_data[1024];
};
template<typename T> class AutoPtr {
public:
    AutoPtr (T* p = NULL) : m_p (p) {}
    AutoPtr (AutoPtr& that) : m_p (that.release ()) {}
    AutoPtr& operator= (AutoPtr& rhs) {
        if (&rhs != this)
            reset (rhs.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;
};
template<typename T> class AutoPtr<T[]> {
public:
    AutoPtr (T* p = NULL) : m_p (p) {}
    AutoPtr (AutoPtr& that) : m_p (that.release ()) {}
    AutoPtr& operator= (AutoPtr& rhs) {
        if (&rhs != this)
            reset (rhs.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;
};
void foo (void) {
    /*
    A a, *pa = &a;
    pa->m_data[0] = 12345;
    (*pa).print (0);
    */
//  A* pa = new A;
    AutoPtr<A> pa (new A);
    pa->m_data[0] = 12345;
//  pa.operator->()->m_data[0] = 12345;
    (*pa).print (0);
//  pa.operator*().print (0);
    AutoPtr<A> pb = pa; // 拷贝构造
    ++pb->m_data[0];
    (*pb).print (0); // 12346
    AutoPtr<A> pc (new A);
    pc->m_data[0] = 22222;
    pb = pc; // 拷贝赋值
    ++pb->m_data[0];
    (*pb).print (0); // 12346
    FILE* fp = fopen ("none", "r");
    if (! fp) {
//      delete pa;
        throw errno;
    }
    // ...
    fclose (fp);
//  delete pa;
}
int main (void) {
    /*
    try {
        foo ();
    }
    catch (int ex) {
        cout << strerror (ex) << endl;
        return -1;
    }
    cout << "成功!" << endl;
    */
//  AutoPtr<A[]> pa (new A[3]);
    AutoPtr<A> pa (new A);
    /*
    auto_ptr<T>
    */
    return 0;
}
 
关于智能指针后续再单独拿出来总结一下, 还不是很清楚....
 

C++STL - 类模板