C++STL(二)类模板
文章目录
- 类模版的声明
- 类模板的使用
- 类模板的静态成员
- 类模板的递归实例化
- 类模板的扩展
- 全局特化
- 局部特化
- 类型形参的缺省值
- 数值形的模版参数
- 模版技巧
bilibili学习地址: https://www.bilibili.com/video/BV1NN4y1F7aY?spm_id_from=333.788.videopod.episodes&vd_source=0fc2f5466dc167b62ed0e5b774c4ab58
类模版的声明
形式:template<class 类型形参1,...> class 类模版名 {...};
例如:
template<class A, class B> class CMath {
public:A m_a;B func() {...};
};# include <iostream>
using namespace std;// 类模板
template<class T>class CMath{
public:CMath(T const& t1, T const const& t2):m_t1(t1), m_t2(t2){}T add();T add() {return m_t1 + m_t2;}
private:T m_t1;T m_t2;
};
// 在模版外实现成员函数:需要帽子和类模板名
template<class T>T CMath<T>::add() {return m_t1 + m_t2;
}int main() {return 0;
}
类模板的使用
使用类模板必须对类模板进行实例化(产生真正的类)
类模板本身并不代表一个确定的类型(即不能用于定义对象),只有通过类型实参实例化成真正的类后才具备类的语义(既可以定义对象)
类模板被实例化时类模板中的成员函数并没有实例化,成员函数只有在被调用的时候才会被实例化。(即产生真正成员函数)注意:成员函数除外
某些类型虽然没有提供类模板所需要的全部功能但照样可以实例化类模板,只要不调用那些未提供功能的成员函数即可。
# include <iostream>
using namespace std;class Interger{
public:Interger(int i):m_i(i){}// 如果不实现操作符+的重载的话,private:int m_i;
};// 类模板
template<class T>class CMath{
public:CMath(T const& t1, T const const& t2):m_t1(t1), m_t2(t2){}T add();T add() {return m_t1 + m_t2;}
private:T m_t1;T m_t2;
};// 在模版外实现成员函数:需要帽子和类模板名
template<class T>T CMath<T>::add() {return m_t1 + m_t2;
}// class CMath<int>{....}
// class CMath<double>{....}
// class CMath<string>{....}
int main() {int nx = 10, ny = 20;CMath<int> m1(nx, ny);cout << m1.add() << endl;double dx = 12.3, dy = 45.6;CMath<double> m2(dx, dy);cout << m2.add() << endl;string sx = "hello", sy = "world";CMath<string> m3(sx, sy);cout << m3.add() << endl;return 0;
}
类模板的静态成员
类模板中的静态成员即不是每个对象拥有一份。也不是类模板拥有一份。而应该是由类模板实例化出的每一个真正的类各自拥有一份。且为该实例化定义的所有对象共享。
# include <iostream>using namespace std;template<class T>class A{
public:static void print() {cout << "&m_i:" << &m_i << "," << "&m_t:" << &m_t << endl;}static int m_i;static T m_t;
};template<class T>int A<T>::m_i = 0;template<class T>T A<T>::m_t = ??;int main() {A<int> x,y,z;x.print();y.print();z.print();A<int>::print();cout << "------------------------" << endl;// 与上四次不一样A<double> m,n,t;m.print();n.print();t.print();A<double>::print();return 0;
}
类模板的递归实例化
可以使用任何类型来实例化类模板。由类模板实例化产生的类也可以用来实例化类模板自身,这种做法称之为类模板的递归实例化。通过这种方法可以构建空间上具有递归特性的数据结构(例如:多维数组)
# include <iostream>using namespace std;template<class T>class Array{
public:T& operator[](size_t i ) {return m_arr[i];}
private:T m_arr[10];};int main() {Array<Array<int> > m;for (int i = 0; i < 10; i++) {for (int j = 0; j < 10; j++) {m[i][j] = i + j;}}for (int i = 0; i < 10; i++) {for (int j = 0; j < 10; j++) {cout << m[i][j] << endl;}cout << endl;}return 0;}
类模板的扩展
全局特化
全类特化:特化一个类模板可以特化该类模板所有的成员函数,相当于重新写了一个针对某种特定数据类型的具体类。
缺陷:特化了全部成员变量,如果只有一个成员需要特化,那么比较费。
成员特化:类模板特化除了可以对整个类进行特化此外,可以只针对某些成员函数进行特化。
# include <iostream>
# include <cstring>using namespace std;template<class T>class CMath{
public:CMath<T>(T const& t1, T const &t2):m_t1(t1),m_t2(t2){}T add() {return m_t1 + m_t2;}private:T m_t1;T m_t2;
};// 全类特化,对哪个类型做全类特化就放在<>里面
template<>class CMath<char* const> {
public:CMath<char* const>(char* const& t1, char* const& t2):m_t1(t1),m_t2(t2){}char* const add() {return strcat(m_t1, m_t2);}
private:char* const m_t1;char* const m_t2;
};// 成员特化,
template<>char* const CMath<char* const>::add(){return strcat(m_t1, m_t2);
}int main() {char cx[256] = "hello", cy[256] = " world";CMath<char* const> m4(cx, cy);m4.add();return 0;
}
局部特化
类模板的局部特化,除非必要否则尽量不要特化,因为特化版本过多容易引发编译器的匹配歧义
# include <iostream>using namespace std;template<class T, class D>class CMath {
public:static void foo() {cout << "1:CMath<T,D>::foo" << endl;}
};// 局部特化
template<class T>class CMath<T, short> {
public:static void foo() {cout << "2:CMath<T,short>::foo" << endl;}
};template<class T>class CMath<T, T> {
public:static void foo() {cout << "3:CMath<T,T>::foo" << endl;}
};template<class T, class D>class CMath<T*,D*> {
public:static void foo() {cout << "4:CMath<T*,D*>::foo" << endl;}
};int main() {CMath<int, double>::foo(); // 1CMath<int, short>::foo(); // 2CMath<short, short>::foo(); //2,3之间会报错,发生匹配歧义CMath<int*, double*>::foo(); // 1CMath<int*, int*>::foo(); // 3,4之间会报错,发生匹配歧义return 0;
}
类型形参的缺省值
类模板的类型形参可以带缺省值。实例化类模板时,如果提供了类型实参则用所提供的类型实参来实例化类模板,如果没有提供类型实参则用相应的类型形参的缺省类型来实例化模版。
如果某一个类型形参具有缺省类型,那么它后面的类型形参都必须带缺省值。
# include <iostream>
# include <typeinfo>using namespace std;template<class T=short, class D=int>class CMath {
public:void print() {cout << "m_t:" << typeid(m_t).name() << "," << "m_d:" << typeid(m_d).name() << endl;}
private:T m_t;D m_d;};int main() {CMath<float, double> m;m.print();CMath<> m2;m2.print();return 0;}
数值形的模版参数
类的类模板的模版形参并不限于类型参数,普通数值也可以作为模版的参数。
# include <iostream>using namespace std;template<class T=double, size_t S=15>class Array{
public:T& operator[](size_t i) {return m_arr[i];}size_t size() {return S;}
private:T m_arr[S]
}int main() {Array<int, 20> a;for (int i = 0; i < a.size(); i++)a[i] = i+1;for (int i = 0; i < a.size(); i++)cout << a[i] << ' ';cout << endl;return 0;
}
模版技巧
模版型成员变量,成员变量,但其类型是由一个类模板实例化的未知类,那么它才可以称之为模版型成员变量。
# include <iostream>using namespace std;template<class T>class Array {
public:T& operator[](size_t i) {return m_arr[i];}
private:T m_arr[10];
};template<class D>class Sum{
public:Sum(Array<D>& s):m_s(s){}D add() {D d = 0;for (int i = 0; i < 10; i++) {d += m_s[i];}return d;}private:Array<D> m_s;
}int main() {Array<int> a;for (int i = 0; i < 10; i++)a[i] = i + 1;Sum<int> s(a);cout << s.add() << endl;return 0;
}
模版型成员函数,类模板的成员函数模版。
# include <iostream>using namespace std;template<class T>class CMath {
public:template<class D>void fook();template<class D>void foo() {cout << "CMath<T>::foo<D>()" << endl;}
};template<class T> template<class D>void CMath<T>::fook() {cout << "CMath<T>::fook<D>()" << endl;
}int main() {CMath<int> m;m.foo<double>();return 0;
}
模版型成员类型,类模板中嵌套的类模板。
# include <iostream>using namespace std;template<class X>class A{
public:template<class Y>class B{public:template<class Z>class C;};
};template<class X>template<class Y>template<class Z>class A<X>::B<Y>::C{
public:template<class T>void foo() {cout << "foo()" << endl; }
};int main() {A<int>::B<double>::C<float> c;c.foo<string>();return 0;
}
模版型模版参数,类模板的模版形参也可以是类模板,可以有缺省值。
# include <iostream>using namespace std;template<class T>class Array {
public:T& operator[](size_t i) {return m_arr[i];}
private:T m_arr[10];
};template<class D, template<class m>class C=Array>class Sum{
public:Sum(Array<D>& s):m_s(s){}D add() {D d = 0;for (int i = 0; i < 10; i++) {d += m_s[i];}return d;}private:C<D> m_s;
}int main() {Array<int> a;for (int i = 0; i < 10; i++)a[i] = i + 1;Sum<int, Array> s(a);cout << s.add() << endl;return 0;
}