# 引例整数和浮点数求绝对值
| int abs(int x) |
| { |
| return x<0? -x:x; |
| } |
| double abs(double x) |
| { |
| return x<0? -x:x; |
| } |
- 解决:函数模版
- 创建一个通用功能的函数
- 支持多种不同形参
- 简化重载函数的函数体设计
| |
| * project : 模版求绝对值 |
| */ |
| #include <iostream> |
| using namespace std; |
| template<typename T> |
| T abs(T x) |
| { |
| return x < 0 ? -x : x; |
| } |
| |
| int main(void) |
| { |
| int n = -5; |
| double d = -5.5; |
| cout << abs(n) << endl; |
| cout << abs(d) << endl; |
| return 0; |
| } |
# 函数模版定义语法
- 语法形式
- 模版参数表的内容
- 类型参数: class (或 typename) 标识符
- 常量参数:类型说明符 标识符
- 模版参数: template <参数表> class 标识符
# 函数模版
| #include <iostream> |
| using namespace std; |
| template <class T> |
| void outputArray(const T* array, int count) |
| { |
| for (int i = 0; i < count; i++) |
| { |
| cout << array[i] << " "; |
| } |
| cout << endl; |
| } |
| |
| int main(void) |
| { |
| const int A_count = 8, B_count = 8, C_count = 20; |
| int a[A_count] = { 1,2,3,4,5,6,7,8 }; |
| double b[B_count] = { 1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8 }; |
| char c[C_count] = "welcome"; |
| cout << "a array contains:" << endl; |
| outputArray(a, A_count); |
| cout << "b array contains:" << endl; |
| outputArray(b, B_count); |
| cout << "c array contains:" << endl; |
| outputArray(c, C_count); |
| return 0; |
| } |
| |
| a array contains: |
| 1 2 3 4 5 6 7 8 |
| b array contains: |
| 1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 |
| c array contains: |
| w e l c o m e |
| */ |
- 注意:
- 一个函数模版并非自动可以处理所有类型的数据
- 只有能够进行函数模版中运算的类型,可以作为类型实参
- 自定义的类,需要重载模版中的运算符,才能作为类型实参
# 类模版的作用
- 使用类模版使用户可以为类声明一种模式,使得类中的某些数据成员,某些成员函数的参数,某些成员函数的返回值,能去 “任意” 类型 (包含基本类型的和用户自定义类型)
# 类模版的声明
| template <模版参数表> |
| class 模版 |
| { |
| 模版声明 |
| } |
- 如果需要在类模版以外定义其成员函数,则要采用以下形式:
template
<模版参数表>- 类型名 类名 <模版参数标识符列表>:: 函数名 (参数表)
- 模版参数表中参数可以声明为该模版类的友元类
- 可通过
typedef
或者 using
对实例化的类模版定义别名
# 模版的默认实参
- 类似于函数形参可有默认实参,函数 / 类模版可有默认模版实参
| template <typename T = double> |
| class Point |
| { |
| public: |
| Point(T _x = 0,T _y = 0):x(_x),y(_y) |
| { |
| |
| } |
| private: |
| T x; |
| T y; |
| } |
# 使用模版
| Point<int> Point(); |
| Point<> Point(); |
# 类模版实例
| #include <iostream> |
| #include <cstdlib> |
| using namespace std; |
| struct Student |
| { |
| int id; |
| float gpa; |
| }; |
| template <class T> |
| class Store |
| { |
| private: |
| T item; |
| bool haveValue; |
| public: |
| friend T; |
| Store(); |
| T& getElem(); |
| void pubElem(const T& x); |
| }; |
| template <class T> |
| Store<T>::Store() :haveValue(false) |
| { |
| } |
| template <class T> |
| T& Store<T>::getElem() |
| { |
| |
| if (!haveValue) |
| { |
| cout << "No item present!" << endl; |
| exit(1); |
| } |
| return item; |
| } |
| template <class T> |
| void Store<T>::pubElem(const T& x) |
| { |
| |
| haveValue = true; |
| item = x; |
| } |
| |
| int main(void) |
| { |
| using IntStore = Store<int>; |
| IntStore s1, s2; |
| s1.pubElem(3); |
| s2.pubElem(-7); |
| cout << s1.getElem() << " " << s2.getElem() << endl; |
| |
| Student g = { 1000,23 }; |
| Store<Student> s3; |
| s3.pubElem(g); |
| cout << "The student id is " << s3.getElem().id << endl; |
| |
| Store<double> d; |
| cout << "Retrieving object D..."; |
| cout << d.getElem() << endl; |
| |
| return 0; |
| } |
| |
| 3 -7 |
| The student id is 1000 |
| Retrieving object D...No item present! |
| */ |
# 群体的概念
- 群体时指由多个数据元素组成的集合体,群体可以分为两个大类:线性群体和非线性群体。
- 线性群体中的元素按位置排列有序,可以区分为第一个元素,第二个元素
- 非线性群体不用位置顺序来标识元素
- vector 就是用类模版实现的动态数组
# 动态数组类模版程序:返回 0~N 的质数
| #pragma once |
| |
| 动态类数组头指针 Array.h |
| */ |
| #ifndef ARRAY_H |
| #define ARRAY_H |
| #include <cassert> |
| template <class T> |
| class Array |
| { |
| private: |
| T* list; |
| int size; |
| public: |
| Array(int sz = 50); |
| Array(const Array<T>& a); |
| ~Array(); |
| Array<T>& operator = (const Array<T> &rhs); |
| T& operator[](int i); |
| const T& operator [](int i) const; |
| operator T* (); |
| operator const T* () const; |
| int getSize() const; |
| void resize(int sz); |
| }; |
| template <class T>Array<T>::Array(int sz) |
| { |
| assert(sz >= 0); |
| size = sz; |
| list = new T[size]; |
| } |
| template <class T>Array<T>::~Array() |
| { |
| delete[] list; |
| } |
| template <class T> |
| Array<T>::Array(const Array<T>& a) |
| { |
| size = a.size; |
| list = new T(size); |
| for (int i = 0; i < size; i++) |
| { |
| list[i] = a.list[i]; |
| } |
| } |
| |
| template <class T> |
| Array<T>& Array<T>::operator=(const Array<T>& rhs) |
| { |
| |
| if (&rhs != this) |
| { |
| if (size != rhs.size) |
| { |
| delete[] list; |
| size = rhs.size; |
| list = new T[size]; |
| } |
| |
| for (int i = 0; i < size; i++) |
| { |
| list[i] = rhs.list[i]; |
| } |
| } |
| return *this; |
| } |
| |
| template <class T> |
| T& Array<T>::operator[](int n) |
| { |
| assert(n >= 0 && n < size); |
| return list[n]; |
| } |
| template <class T> |
| const T & Array<T>::operator[] (int n) const |
| { |
| assert(n >= 0 && n < size); |
| return list[n]; |
| } |
| |
| template <class T> |
| Array<T>::operator T* () |
| { |
| return list; |
| } |
| |
| template<class T> |
| int Array<T>::getSize() const |
| { |
| return size; |
| } |
| |
| template <class T> |
| void Array<T>::resize(int sz) |
| { |
| assert(sz >= 0); |
| if (sz == size) |
| return; |
| T* newList = new T[sz]; |
| int n = (sz < size) ? sz : size; |
| |
| for (int i = 0; i < n; i++) |
| { |
| newList[i] = list[i]; |
| } |
| delete[] list; |
| list = newList; |
| size = sz; |
| } |
| #endif |
| |
| #include "Array.h" |
| #include <iostream> |
| #include <iomanip> |
| using namespace std; |
| void read(int* p, int n) |
| { |
| for (int i = 0; i < n; i++) |
| { |
| cin >> p[i]; |
| } |
| } |
| int main(void) |
| { |
| |
| Array<int>a(3); |
| |
| int n, count = 0; |
| cout << "Enter a value > = 2 as upper limit for prime number:"; |
| cin >> n; |
| for (int i = 2; i <= n; i++) |
| { |
| bool isPrime = true; |
| for (int j = 0; j < count; j++) |
| { |
| if (i % a[j] == 0) |
| { |
| isPrime = false; |
| break; |
| } |
| } |
| if (isPrime) |
| { |
| if (count == a.getSize()) |
| a.resize(count * 2); |
| a[count++] = i; |
| } |
| } |
| for (int i = 0; i < count; i++) |
| { |
| cout << setw(8) << a[i]; |
| } |
| cout << endl; |
| return 0; |
| } |
# 链表类模版
| #pragma once |
| #ifndef NODE_H |
| #define NODE_H |
| |
| template <class T> |
| class Node |
| { |
| private: |
| Node<T>* next; |
| public: |
| T data; |
| Node(const T& item, Node<T>* next = 0); |
| void insertAfter(Node<T>* p); |
| Node<T>* deleteAfter(); |
| Node<T>* nextNode(); |
| const Node<T>* nextNode() const; |
| }; |
| |
| |
| template <class T> |
| Node<T>::Node(const T& data, Node<T>* next = 0) |
| :data(data), next(next) |
| { |
| } |
| |
| template <class T> |
| Node<T>* Node<T>::nextNode() |
| { |
| return next; |
| } |
| |
| template <class T> |
| const Node<T>* Node<T>::nextNode() const |
| { |
| return next; |
| } |
| |
| |
| template <class T> |
| void Node<T>::insertAfter(Node<T>* p) |
| { |
| |
| p->data = next; |
| next = p; |
| } |
| |
| template <class T> |
| Node<T>* Node<T>::deleteAfter(void) |
| { |
| Node<T>* tempPtr = next; |
| if (next == 0) |
| return 0; |
| next = tempPtr->next; |
| return tempPtr; |
| } |
| #endif |