-
函数模板的基本概念
template <typename T> void Swap(T& a, T& b) { T tmp = a; a = b; b = tmp; } Swap<int>(a, b); // 手动指定使用int数据类型的模板 Swap(a, b); // 编译器自动推导 -
函数模板的注意事项
- 虚函数和析构函数不能使用模板,其他函数可以,包括构造函数
class Student { public: template <typename T> Student(T a) { cout << "a=" << a << endl; } template <typename T> void show(T b) { cout << "b=" << b << endl; } };- 函数模板也可以重载
template <typename T> void func(T a) { cout << "a = " << a << endl; } template <typename T1, typename T2> void func(T1 a, T2 b) { cout << "a = " << a << ", b = " << b << endl; } template <typename T1, typename T2> void func(T1 a, T2 b, int c) { cout << "a = " << a << ", b = " << b << ", c = " << c << endl; }- 使用函数模板时,如果显示指定了函数模板的数据类型,那么可以发生隐式类型转换
template <typename T> void show(T a, T b) { cout << a << " " << b << endl; } int main() { int a = 10; char b = 20; show<int>(a, b); // 自动将b转换成int return 0; } -
函数模板的具体化
- 就是函数模板中的一种特殊情况,指定参数的类型
template <typename T> void show(T a, T b) { cout << "show(T a, T b)" << endl; } template <> void show(int a, int b) { cout << "show(int a, int b)" << endl; } int main() { int a = 10; int b = 20; show(a, b); return 0; }- 函数调用优先级问题
1. 普通函数 > 具体化 > 函数模板 2. 如果函数模板能更好的匹配,那么会优先使用函数模板 3. 可以通过加<>来强制使用函数模板 -
函数模板分文件编写
- 普通函数的声明放在头文件中,定义放在源文件中
- 函数模板只是函数的描述,没有实体,放在头文件中
- 具体化模板和普通函数一样
-
函数模板高级
- 如果decltype里面加括号了,那么就是引用类型
- 如果是左值,也是引用(通俗来讲,左值是指可以放在赋值运算符左侧的表达式,可以寻址,可被修改)
- 其他的都是和decltype里面的标识符类型一致。
- 如果里面是函数,函数名 => 指针类型,函数 => 函数的返回值类型
decltype(a) b1; // 和a相同 decltype(func()) b2; // 和函数返回值相同 decltype(func) *b3 = func; b3(); // b 是函数类型的指针, 可以当函数用 decltype((func)) b4 = func; b4(); // 对函数名加了括号,那么b是函数的引用,也可以直接调用 decltype((a)) b5 = x; // 加了括号的标识符,那么b是引用 decltype(++a) b6 = x; // 表达式是左值,b也是引用 -
模板类的基本概念
- 模板类使用的时候必须指定数据类型
- 可以指定缺省值
- 模板类的函数也可以在类外定义,但是不能指定缺省值
template <class T1, class T2 = string> class AA { public: T1 m_a; T2 m_b; AA() {} AA(T1 a, T2 b) : m_a(a), m_b(b) {} T1 func(); }; template<class T1, class T2> T1 AA<T1, T2>::func() { cout << m_a << endl; return m_a; } -
模板类的示例-栈
- delete [] 用于删除动态分配数组的内存(new动态分配)
- delete 用来删除动态分配的单个对象的内存
template <class Datatype> class Stack { private: Datatype* vv; int size; int top; public: Stack() {} Stack(int size_) : size(size_), top(0) { vv = new Datatype[size_]; } ~Stack() { delete[] vv; // int 型用delete, string 型用delete[] vv = nullptr; } bool isempty() { return top == 0; } bool isfull() { return top == size; } bool push(const Datatype& x) { if (isfull()) { cout << "栈满" << endl; return false; } vv[top++] = x; return true; } bool pop(Datatype& x) { if (isempty()) { cout << "栈空" << endl; return false; } x = vv[--top]; return true; } }; int main() { //Stack<int> st(5); //st.push(1); //st.push(2); //st.push(3); //st.push(4); //st.push(5); Stack<string> st(5); st.push("hello"); st.push("king"); string item; while (!st.isempty()) { st.pop(item); cout << item << endl; } return 0; } -
模板类的示例-数组
- string是类,不能用memset初始化。memset会将字符数组的每个字节都设置为给定的值,可能会破坏string的内部结构
template <class Datatype, int len> // 非通用数据类型用来指定数组大小 class Array { // 定长数组 private: Datatype* arr; public: Array() { arr = new Datatype[len]; } ~Array() { delete[] arr; arr = nullptr; } Datatype& operator[](int index) { return arr[index]; } const Datatype& operator[](const int& index) const { return arr[index]; } };template <class T> class Vector { // 变长数组 private: int len; T* vec; public: Vector(int size = 10) : len(size) { vec = new T[size]; } ~Vector() { delete[] vec; vec = nullptr; } T& operator[](int index) { return vec[index]; } const T& operator[](int index) const { return vec[index]; } void resize(int size) { if (size <= len) return; T* newvec = new T[size]; for (int i = 0; i < len; ++i) newvec[i] = vec[i]; delete[] vec; vec = newvec; len = size; } }; -
嵌套使用模板类
template <class Datatype> class Stack { private: Datatype* vv; int size; int top; public: Stack(int size_ = 3) : size(size_), top(0) { vv = new Datatype[size_]; } ~Stack() { delete[] vv; vv = nullptr; } Stack& operator=(const Stack& st) { delete[] vv; size = st.size; top = st.top; vv = new Datatype[size]; for (int i = 0; i < size; ++i) vv[i] = st.vv[i]; return *this; } bool isempty() { return top == 0; } bool isfull() { return top == size; } bool push(const Datatype& x) { if (isfull()) { cout << "栈满" << endl; return false; } vv[top++] = x; return true; } bool pop(Datatype& x) { if (isempty()) { cout << "栈空" << endl; return false; } x = vv[--top]; return true; } }; template <class T> class Vector { private: int len; T* vec; public: Vector(int size = 2) : len(size) { vec = new T[size]; } ~Vector() { delete[] vec; vec = nullptr; } Vector& operator=(const Vector& v) { delete[] vec; len = v.len; vec = new T[len]; for (int i = 0; i < len; ++i) vec[i] = v.vec[i]; return *this; } T& operator[](int index) { if (index >= len) resize(index + 2); return vec[index]; } const T& operator[](int index) const { return vec[index]; } void resize(int size) { if (size <= len) return; T* newvec = new T[size]; for (int i = 0; i < len; ++i) newvec[i] = vec[i]; //注意这里,如果Vector内部的数据不是默认数据类型并且使用了堆区内存的话,会涉及到浅拷贝问题,此处内部是Stack,因此Stack要提供深拷贝,否则会出错 delete[] vec; vec = newvec; len = size; } }; int main() { Vector<Stack<int>> vec; vec[0].push(1); vec[0].push(2); vec[0].push(3); vec[1].push(4); vec[1].push(5); vec[1].push(6); vec[2].push(7); vec[2].push(9); for (int i = 0; i < 3; ++i) { int item; while (vec[i].isempty() == false) { vec[i].pop(item); cout << item << " "; } cout << endl; } return 0; } -
模板类具体化
- 优先级:完全具体化 > 部分具体化 > 普通模板类
template <class T1, class T2> class A { public: A() { cout << "普通模板类" << endl; } }; template <class T1> class A<T1, string> { public: A() { cout << "部分具体化" << endl; } }; template <> class A<int, string> { public: A() { cout << "完全具体化" << endl; } }; -
模板类与继承
- 派生类需要在初始化列表中指明基类的构造函数
- 模板类继承普通类
class AA { public: int c_; AA(int c) : c_(c) { cout << "调用了AA(int c) 构造函数" << endl; } }; template <class T1, class T2> class BB : public AA { public: T1 a_; T2 b_; BB(const T1 a, const T2 b, int c) : AA(c), a_(a), b_(b) { cout << "调用了BB(const T1 a, const T2 b) 构造函数" << endl; } };- 普通类继承模板类的实例化版本
template <class T1, class T2> class BB { public: T1 a_; T2 b_; BB(const T1 a, const T2 b) : a_(a), b_(b) { cout << "调用了BB(const T1 a, const T2 b) 构造函数" << endl; } }; class AA : public BB<int, string> { public: int c_; AA(int c, const int a, const string b) : BB<int, string>(a, b), c_(c) { cout << "调用了AA(int c, const int a, const string b) 构造函数" << endl; } };- 普通类继承模板类
template <class T1, class T2> class BB { public: T1 a_; T2 b_; BB(const T1 a, const T2 b) : a_(a), b_(b) { cout << "调用了BB(const T1 a, const T2 b) 构造函数" << endl; } }; template <class T1, class T2> class AA : public BB<T1, T2> { public: int c_; AA(int c, const T1 a, const T2 b) : BB<T1, T2>(a, b), c_(c) { cout << "调用了AA(int c, const T1 a, const T2 b) 构造函数" << endl; } };- 模板类继承模板类
template <class T1, class T2> class BB { public: T1 a_; T2 b_; BB(const T1 a, const T2 b) : a_(a), b_(b) { cout << "调用了BB(const T1 a, const T2 b) 构造函数" << endl; } }; template <class T, class T1, class T2> class CC : public BB<T1, T2> { public: int d_; CC(int d, T1 a, T2 b) : BB<T1, T2>(a, b), d_(d) { cout << "调用了 CC(int d) 构造函数" << endl; } };- 模板类继承模板参数给出的基类
template <class T> class AA { public: AA() { cout << "调用了AA()构造函数" << endl; } }; template <class T1, class T2> class BB { public: T1 a_; T2 b_; BB() { cout << "调用了BB() 构造函数" << endl; } BB(T1 a, T2 b) : a_(a), b_(b) { cout << "调用了BB(T1 a, T2 b)构造函数" << endl; } }; template <class T> class DD : public T{ public: DD() { cout << "调用了DD()构造函数" << endl; } DD(int a, string b) : T(a, b) { cout << "调用了DD(int a, string b) 构造函数" << endl; } }; -
模板类与函数
// 普通函数,参数和返回值是模板类的一个实例化版本 AA<int, string> func(AA<int, string>& aa) { aa.show(); cout << "调用了AA<int, string> func" << endl; return aa; } // 适用于AA类的函数模板 template <typename T1, typename T2> AA<T1, T2> func(AA<T1, T2>& aa) { aa.show(); cout << "调用了AA<T1, T2> func" << endl; return aa; } // 通用函数模板 template <typename T> T func(T& t) { t.show(); cout << "调用了T func()" << endl; return t; } -
模板类与友元
- 非模板友元
template <class T1, class T2> class AA { friend void func(AA<int, string>& a); friend void func(AA<int, int>& a); private: T1 a_; T2 b_; public: AA(T1 a, T2 b) : a_(a), b_(b) {} void show() { cout << "a_ = " << a_ << ", b_ = " << b_ << endl; } }; void func(AA<int,string>& a) { cout << "func: aa = " << a.a_ << ", b_ = " << a.b_ << endl; } void func(AA<int, int>& a) { cout << "func: aa = " << a.a_ << ", b_ = " << a.b_ << endl; }- 约束模板友元
template <typename T> // 第一步 声明。可用于多个模板类 void func(T& t); template <class T1, class T2> class AA { friend void func<>(AA<T1, T2>& t); // 第二步 private: T1 a_; T2 b_; public: AA(T1 a, T2 b) : a_(a), b_(b) {} void show() { cout << "a_ = " << a_ << ", b_ = " << b_ << endl; } }; template <class T1, class T2> class BB { friend void func<>(BB<T1, T2>& t); private: T1 a_; T2 b_; public: BB(T1 a, T2 b) : a_(a), b_(b) {} void show() { cout << "a_ = " << a_ << ", b_ = " << b_ << endl; } }; template <typename T> // 第三步 通用类型 void func(T& t) { cout << "通用 func: a_ = " << t.a_ << ", b_ = " << t.b_ << endl; } template <> // 第三步 具体化 void func(AA<int, string>& t) { cout << "具体化 func: a_ = " << t.a_ << ", b_ = " << t.b_ << endl; } -
模板类的成员模板
template <class T1, class T2> class AA { public: T1 a_; T2 b_; AA(T1 a, T2 b) : a_(a), b_(b) {}; void show() { cout << "AA a_ = " << a_ << ", AA b_ = " << b_ << endl; } template <class T> // 嵌套类模板 class BB { public: T x_; T1 y_; BB() {} BB(T x, T1 y) : x_(x), y_(y) {} void show() { cout << "BB x_ = " << x_ << ", y_ = " << y_ << endl; } }; BB<int> bb; template <typename T> // 嵌套模板函数 void show(T& t) { cout << "t = " << t << endl; show(); bb.show(); } }; int main() { AA<int, string> a(1, "mary"); a.bb.x_ = 1; a.bb.y_ = 2; string str = "hello mary"; a.show(str); return 0; } -
将模板类用作参数
template <class T, int len> class LinkList { T* head_; int len_ = len; public: void insert() { cout << "向链表中插入一个元素" << endl; } void Delete() { cout << "在链表中删除一个元素" << endl; } void modify() { cout << "修改链表中的一个元素" << endl; } }; template <class T, int len> class Array { T* arr; int len_ = len; public: void insert() { cout << "向数组中插入一个元素" << endl; } void Delete() { cout << "在数组中删除一个元素" << endl; } void modify() { cout << "修改数组中的一个元素" << endl; } }; template <template<class, int>class T, class T1, int len> class XX { public: T<T1, len> table; void insert() { table.insert(); } void Delete() { table.Delete(); } void modify() { table.modify(); } };