C++入门自学Day6-- C++模版
往期内容回顾
C/C++内存管理(初识)
C/C++内存管理(续)
一、泛型编程
1、什么是泛型编程(Generic Programming)
泛型编程 是一种编程范式,其核心思想是:
编写独立于数据类型的算法或数据结构,使其可以应用于多个类型之上。
换句话说,不管你是对 int、double、string 还是自定义类型操作,都可以使用同一个函数或类模板。
二、C++ 模板介绍
C++ 提供了两种模板:
1. 函数模板(Function Template)
定义格式:
template<typename T> T Max(T a, T b) {return a > b ? a : b; }
举个例子:
template<typename T> void Swap(T& a,T& b){T tmp = a;a = b;b =tmp; };int main(){double a = 12.1;double b = 2;Swap(a,b);cout<<"a = "<<a<<" b = "<<b<<endl; }
注意:调用函数模版实例化生成的对应类型的函数,如果T = int则实例化int类型的swap函数。在预处理阶段模版实例化推演成对应类型的函数。
2. 类模板(Class Template)
定义格式:
利用模版可实例化自定义栈类型,存放整型数据,浮点型的栈。
template<class T> class Vector{public:Vector():_a(nullptr),_top(0),_capacity(0){};~Vector(){delete[] _a;_top = 0;_capacity =0;};//类内函数声明void push_back(const T& x);void pop_back(); private:T* _a;size_t _top;size_t _capacity; }; // 类外面定义函数 template<class T> void push_pop(){ }; void pop_back(){ };
template<typename T> class Stack { public:void push(const T& val) { data.push_back(val); }void pop() { data.pop_back(); }T top() const { return data.back(); }bool empty() const { return data.empty(); } private:std::vector<T> data; };int main(){Stack<int> s1; }
3. 模板与泛型编程的关系
模板 | 泛型编程 |
---|---|
是泛型编程在 C++ 中的语言机制 | 是一种更高层次的思想/设计模式 |
编译期生成具体类型的代码 | 设计期考虑如何让算法与类型解耦 |
C++ 模板实现了泛型编程思想 | STL 是泛型编程的典范 |
4、模板优点与缺点
优点:
-
代码复用性高:避免重复编写多份类似函数/类。
-
类型安全:编译期检查。
-
性能好:模板代码在编译期展开,不影响运行效率。
缺点:
-
可读性差:报错信息复杂。
-
编译时间长:模板实例化多。
-
代码膨胀:每个类型实例化一次,可能增加编译后的体积。
5、模版总结
项目 | 内容 |
---|---|
本质 | 模板是编译期的代码生成工具 |
类型 | 函数模板、类模板 |
作用 | 泛化函数和类,支持多种类型 |
与泛型编程关系 | 模板是泛型编程的语言支持,泛型编程是一种设计思想 |
代表应用 | STL(如 vector、map、algorithm 等) |
三、模版编程实现顺序表Vector
1、Vector类的定义
template<class T> class Vector{public://初始化列表Vector():_top(0),_capacity(10){_a = new T[_capacity];};//析构函数~Vector(){delete[] _a;_top = 0;_capacity =0;};//类内函数声明void push_back(const T& x);void pop_back(); // 运算符重载T& operator[](size_t i){assert(i<_top);return _a[i];}size_t size(){return _top;}private:T* _a;size_t _top;size_t _capacity; };
2、类外函数定义:
//类外的函数定义 template<class T> void Vector<T>::push_back(const T& x){//空间不够if(_top == _capacity){size_t new_capacity = 2*_capacity;T* tmp = new T[new_capacity];if(_a){memcpy(tmp,_a,sizeof(T)*_top);delete [] _a;}_a = tmp;_capacity = new_capacity;}else{ _a[_top++] = x;} };
template<class T> void Vector<T>::pop_back(){assert(_top>0);_top--; };
主函数调用:
int main(){Vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);for(int i =0;i<v.size();i++){v[i]*=2;};for(int i =0;i<v.size();i++){cout<<v[i]<<" ";};cout<< endl;}
输出描述:
2 4 6
四、函数模版的实例化
什么是模板实例化?
模板实例化(Instantiation)**指的是:编译器根据模板参数类型,生成对应的具体函数或类代码的过程。
隐氏实例化
template<typename T> T add(T& a,T& b){return a+b; };
int main(){int a = 1;int b =2;double c = 2.1;double d = 1.2;cout<<"a + b = "<< add(a,b)<<endl;实例化为 int add(int, int)cout<<"c + d = "<< add(c,d)<<endl; 实例化为double add(double, double) }
输出描述:
a + b = 3
c + d = 3
显式实例化
// 显示实例化 (指定 T 的类型)cout<<"a + b = "<<add<int>(a,b);
你可以主动告诉编译器实例化某个版本:
template int add<int>(int, int); // 告诉编译器生成这个版本,无需调用
函数模板是 在使用时才实例化,这意味着:
不使用不会实例化,不会生成代码
必须 模板函数的定义可见,才能实例化成功(通常模板放头文件中)
五、函数模板 vs 普通函数的优先级
普通函数的优先级 >> 函数模版
void add(int a, int b) {cout << "普通函数" << endl; } template <typename T> T add(T a, T b) {cout << "模板函数" << endl;return a + b; } add(1, 2); // 调用普通函数
六、函数模版实例化图解
template <typename T>
↓
用户调用:add(1.0, 2.0)
↓
编译器推导:T = double
↓
实例化:生成 double add(double, double)
↓
参与编译,生成可执行代码
总结
-
函数模板提供类型参数化的机制,实现泛型编程。
-
实例化是编译器根据调用自动或显式生成对应代码的过程。
-
模板代码通常放在头文件中。
-
函数模板实例化支持隐式、显式、特化等方式。