Template
function template
函数模板就是建立一个通用的函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。
template< typename T >(class和typename都行)
1 2 3 4
| 参数类型自动推导 Max(x,y); 显示类型调用 Max<int>(x,y);
|
template function
调用函数模板,编译器私底下会 根据传过来的变量创建对应的函数,将它具体化。——这就是通过编译生成的模板函数。
小结:
- 我们注意到,函数模板和函数重载似乎很类似,当他们两个并存时,如果参数类型和普通函数更匹配,就调用普通函数。
- 不存在普通函数,函数模板会隐式类型转换吗?不会。不提供隐式的类型转换,必须是严格的匹配。
- 如果显式的调用函数模板,则使用<>类型列表。
- 如果函数模板会产生更好的匹配,使用函数模板。
- 当所传参数需要隐式类型转换时,优先调用普通函数。
- 函数模板也可以重载。
- 编译器并不是把函数模板处理成能够处理任意类型的函数。
- 编译器从函数模板通过具体的参数类型产生不用的函数。
class template
类模板创建对象,必须显式指定类型。
类模板用于实现类所需数据的类型参数化。
类模板在表示支持多种数据结构显得特别重要,这些数据结构的表示和算法不受所包含的元素类型的影响。
类模板与继承:
1.父类是一般类,子类时模板类,和普通继承类似。
2.子类是一般类,父类是模板类, 继承时必须在子类中实例化父类参数。
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| template <typename T> class A { public: A(T t = 0) :t(t) {
} ~A() {
} T getT()const { return this->t; } private: T t; };
class B:public A<int> { public: B(int b = 0) :A<int>(b) {
}
private: int b; };
|
3.父类和子类都是模板时,子类的虚拟类型可以传递到父类中。
类模板的写法注意:
- 写在类外面时,要加参数列表, 并且要声明模板(class name< 参数列表 >)
- 类模板定义和声明分开写,包含主函数的.cpp 要包含”该类声明的.cpp”
书写实例:
(就是基本上只要在类外写定义的有类名的位置后面都要写上< T >,除了构造析构函数,其实写上也没事,只是警告让用新的书写形式。)
(不建议使用太多的友元函数)
类模板和友元函数:
在类外实现成员函数要先声明一下模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| #include<iostream> using namespace std;
template<typename T> class A { public: A(T a= 0); T& getT()const; A operator+(const A& other); void print()const; ~A(); template<typename T> friend A<T> addA(const A<T>& a, const A<T>& b); private: T t; };
template<typename T> A<T>::A(T a) : t(a) {
} template<typename T> A<T>::~A() {
} template<typename T> A<T> A<T>::operator+(const A<T>& other) { A<T> tmp; tmp.t = this->t + other.t; return tmp; } template<typename T> void A<T>::print()const { cout << this->t << endl; }
template<typename T> T& A<T>::getT()const { return this->t; }
template<typename T> A<T> addA(const A<T>& a, const A<T>& b) { A<T> temp; temp.t = a.t + b.t; return temp; }
int main(void) { A<int> a(100); a.print(); A<int> b(200); A<int>temp = addA<int>(a,b); temp.print(); return 0; }
|
小结:
- 类模板内部声明友元函数,也要声明一下模板先。
- 类模板成员函数内部从创建的对象别忘了加< T >。
- 友元函数调用,函数名后也要显示指定类型。
类模板和static数据成员
类外赋初值
1 2
| template<typename T> int A<T>::count = 666;
|
虚拟类型T被实例化的类型不同,所调用的内容也不同。
注意以下代码的静态变量变化即可了解。
同意类模板的虚拟类型T被实例化的类型相同,静态变量是同一个。
1 2 3 4 5 6 7 8 9 10
| A<int>a(100); A<int>b(200); a.count = 888; cout << a.count << endl; cout << b.count << endl;
A<float>c(1.0); A<float>d(2.0); cout << c.count << endl; cout << d.count << endl;
|
静态成员数据也可以使用虚拟类型参数。
效果同上。
1 2
| public: static T count;
|
小补充:
类的成员函数不能调用我们下面成员函数重载的运算符。(貌似)
类模板重载左移 在声明中加一个< T >,让编译通过。
1 2
| template<typename T> friend ostream& operator<< <T>(ostream& out, const Vector<T>& object);
|
(自定义)容器中放入类,该类需要有默认构造函数。
自定义容器中存放自定义类对象,该容器重载了<<,想要按照下标cout<<,那么该类也要重载<<。
练习:实现一个自定义Vector类
Vector.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include <iostream>
using namespace std;
template <typename T> class Vector { template<typename T> friend ostream& operator<< <T>(ostream& out, const Vector<T>& object); public: Vector(int size = 128); Vector(const Vector& object); int getLength(); T& operator[](int index); Vector& operator=(const Vector& object); ~Vector(); /
private: T* m_base; int m_len; };
|
Vector.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| #include <iostream> using namespace std; #include "Vector.h"
template<typename T> ostream& operator<<(ostream& out, const Vector<T>& object) { for (int i = 0; i < object.m_len; i++) { out << object.m_base[i] << " "; } out << endl;
return out; }
template <typename T> Vector<T>::Vector(int size) { if (size > 0) { m_len = size; m_base = new T[m_len]; } }
template <typename T> Vector<T>::Vector(const Vector<T>& object) {
m_len = object.m_len; m_base = new T[m_len]; for (int i = 0; i < m_len; i++) { m_base[i] = object.m_base[i]; } } template <typename T> int Vector<T>::getLength() { return m_len; }
template <typename T> T& Vector<T>::operator[](int index) { return m_base[index]; }
template <typename T> Vector<T>& Vector<T>::operator=(const Vector<T>& object) { if (m_base != NULL) { delete[] m_base; m_base = NULL; m_len = 0; } m_len = object.m_len; m_base = new T[m_len]; for (int i = 0; i < m_len; i++) { m_base[i] = object.m_base[i]; } return *this; }
template <typename T> Vector<T>::~Vector() { if (m_base != NULL) { delete[] m_base; m_base = NULL; m_len = 0; } }
|
main.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
| #include"Vector.cpp" #include<iostream> #include<string> using namespace std;
class Student { public: Student() { age = 0; name = '\0'; }
Student(int _age, string _name):name(_name),age(_age) { }
void print() { cout << name << ", " << age << endl; }
~Student() {
} friend ostream& operator<<(ostream& os, const Student& stu);
private: string name; int age; };
ostream& operator<<(ostream& os, const Student& stu) { os << stu.age << " " << stu.name << endl; return os; }
int main(void) {
Student s1(18, "张三"); Student s2(18, "张四");
Vector<Student> myStudent(2); myStudent[0] = s1; myStudent[1] = s2; for (int i = 0; i < myStudent.getLength(); i++) { cout << myStudent[i] << endl; }
return 0; }
|