C++学习笔记:09 函数模板与类模板
2021-09-15 14:12
429 查看
引入
考虑一个求绝对值函数myabs,对于int,double,float等数据类型需要重载多次,编写多个函数体。函数体逻辑代码完全一致,仅仅是数据类型不同。
在这种情况下,可以使用函数模板
#include <iostream> using namespace std; int myabs(int x) { return x >= 0 ? x : -x; } float myabs(float x) { return x >= 0 ? x : -x; } double myabs(double x) { return x >= 0 ? x : -x; } int main() { cout << myabs(1) << endl; cout << myabs(1.1) << endl; cout << myabs(1.2) << endl; return 0; }
myabs()函数可以使用模板函数申明
template<class T> T myabs(T x) { return x >= 0 ? x : -x; }
函数模板
函数模板定义语法
template <模板参数表> 函数定义
模板参数表的内容:
- **类型参数:**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() { 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 <模板参数表> 类型名 类名<模板参数标识符列表>::函数名(参数表)
注意:
- 模板类的声明与定义需要放在同一文件内
- 模板类中重载<<,只能在类体里面实现,在类外写定义不好使
#include <iostream> using namespace std; struct Student { int id; float gpa; public: friend ostream& operator <<(ostream& os, const Student& in); }; ostream& operator << (ostream& os, const Student& in) { os << "ID:" << in.id << " " << "GPA:" << in.gpa << endl; return os; } template<class T> class Store { private: T item; bool haveValue; public: Store(); T& getElem(); void putElem(const T& e); }; template<class T> Store<T>::Store() { this->haveValue = false; } template<class T> T& Store<T>::getElem() { if (!haveValue) { cout << "No item present!" << endl; } return this->item; } template<class T> void Store<T>::putElem(const T& e) { this->haveValue = true; this->item = e; } int main() { Store<int> s1, s2; s1.putElem(3); s2.putElem(-7); cout << s1.getElem() << " " << s2.getElem() << endl; Student g = { 1000, 23 }; Store<Student> s3; s3.putElem(g); cout << s3.getElem() << endl; Store<double> d; cout << "Retrieving object D... "; cout << d.getElem() << endl; return 0; } /* output 3 -7 ID:1000 GPA:23 Retrieving object D... No item present! -9.25596e+61 */
例子
Array数组类
#include <iostream> #include <iomanip> using namespace std; 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); //overload = T& operator [](int i); //overload [] const T& operator [](int i) const; //overload [] operator T* (); operator const T* () const; int getSize() const; void resize(int sz); void fill(T in) { for (int i = 0; i < this->size; i++) this->list[i] = in; } friend ostream& operator <<(ostream& os, const Array<T>& e) { os << "size of array = " << e.size << endl; for (int i = 0; i < e.size; ++i) os << e.list[i] << " "; os << endl; return os; } }; template<class T> Array<T>::Array(int sz) { this->size = sz; this->list = new T[this->size]{}; } template<class T> Array<T>::~Array() { delete[] this->list; } template<class T> Array<T>::Array(const Array<T>& a) { this->size = a.size; this->list = new T[this->size]; for (int i = 0; i < this->size; ++i) { this->list[i] = a.list[i]; } } template<class T> Array<T>& Array<T>::operator =(const Array<T>& rhs) { if (&rhs != this) { if (this->size != rhs.size) { delete[] this->list; size = rhs.size; list = new T[this->size]; } for (int i = 0; i < this->size; ++i) this->size[i] = rhs.size[i]; } return *this; } template<class T> T& Array<T>::operator [](int i) { return this->list[i]; } template<class T> const T& Array<T>::operator [](int i) const { return this->list[i]; } //重载指针转换运算符 template<class T> Array<T>::operator T* () { return list; } template<class T> Array<T>::operator const T* () const { return list; } template<class T> int Array<T>::getSize() const { return this->size; } template<class T> void Array<T>::resize(int sz) { if (sz == this->size) return; T* newlist = new T[sz]{}; int n = (sz < this->size) ? sz : this->size; for (int i = 0; i < n; ++i) newlist[i] = this->list[i]; delete[] this->list; list = newlist; this->size = sz; } int main() { Array<int> a(10); int n, count = 0; cout << "Enter a value >= 2 as upper limit for prime numbers: "; cin >> n; //求给定范围内的质数 for (int i = 2; i <= n; i++) { bool isPrime = true; for (int j = 0; j < count; j++) //若i被a[j]整除,说明i不是质数 if (i % a[j] == 0) { isPrime = false; break; } if (isPrime) { if (count == a.getSize()) a.resize(count * 2); a[count++] = i; } } cout << a; return 0; } /* Enter a value >= 2 as upper limit for prime numbers:20 size of array = 10 2 3 5 7 11 13 17 19 0 0 */
以上例子中重载指针运算符
//重载指针转换运算符 template<class T> Array<T>::operator T* () { return list; } template<class T> Array<T>::operator const T* () const { return list; } /* 后置const是为了让常对象能调用这个成员函数(常对象只能调用常成员函数,不能调用普通成员函数);“const T*”表示,通过对象名创建动态数组后,通过对象名不能改变数组 */
为什么要重载指针运算符?参考链接
void read(int* p, int n) { for (int i = 0; i < n; i++) cin >> p[i]; } int main() { Array<int> a(10); read(a, 5); cout << a; return 0; }
调用read函数并传入Array类型指针时,因为read函数只接受int类型指针,所以会自动搜索从Array型指针到int型指针的转换方式,如果能搜索到,就执行转换,把转换后的指针交给read函数,搜索不到,编译器就会报错。
虽然重载了指针转换运算符,但是其作用只是为了能把对象名a当类内动态数组名list一样,传入类外函数的参数表作形实结合(实参是对象名,形参是T型指针);
光重载指针转换运算符还不够,要想对象名能像数组名一样使用下标,还要重载下标运算符。
如果接着在main函数写a[i],编译器是不会把这里的a当作数组名,所以仅仅是写a[i]是无法调用数组元素的(编译器不认这种代码),只有重载了下标运算符“[ ]”,编译器才会把a[i]当成list[i];
总结:
重载指针运算符,作用仅限于把“a”转换成“list”;重载下标运算符,作用仅限于把“a[i]”转换成“list[i]”;
相关文章推荐
- c++ 模板学习笔记:类模板和函数模板实现pair(权哥)
- C++学习笔记--函数模板
- 设计模式C++学习笔记之九(Template Method模板方法模式)
- C++学习笔记十六-模板和泛型编程(二)
- 设计模式C++学习笔记之九(Template Method模板方法模式)
- C++学习笔记之:模板
- C++库研究笔记——使用函数模板还是类模板?+ 一个类型重复问题的两种解决方法
- c++ 模板学习笔记:函数模板的类型识别(权哥)
- PKU C++程序设计实习 学习笔记5 文件操作和模板
- C++学习笔记十六-模板和泛型编程(二)
- 学习笔记-简单模板链表类的C++实现 15/10/25
- c++学习笔记之类模板中的友元声明
- c++学习笔记之成员模板
- <C++学习笔记>函数模板 template
- C++学习笔记12-模板1
- C++学习笔记09:打印 n 阶实心菱形
- C++学习笔记十六-模板和泛型编程(一)
- 嵌入式开发之C++基础学习笔记5--静态成员,友元,运算符重载,模板,文件流
- C++ 模板学习 函数模板、类模板、迭代器模板
- C++ Standard Stl -- SGI STL源码学习笔记(03) STL中的模板编译期检查与偏特化编译期检查