ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

【C++】库函数学得很昏?可能是模板还没有理解好

【C++】库函数学得很昏?可能是模板还没有理解好 目录泛型编程函数模板函数模板的实例化隐式类型实例化显式类型实例化匹配规则类模板非类型模版参数模板的特化模板的分离编译泛型编程void Swap(int left, int right) { int temp left; left right; right temp; } void Swap(double left, double right) { double temp left; left right; right temp; } void Swap(char left, char right) { char temp left; left right; right temp; }在学习C语言的时候学习过交换的函数这里用到C的引用交换但是可以看到如果对每一种类型都写一个交换的函数是特别的冗余他们仅仅是类型不同代码复用率低每当有新的类型出现的时候就要写一个新的函数为了解决这个问题就有了泛型编程。泛型编程编写与类型无关的通用代码是代码复用的一种手段。模板是泛型编程的基础。函数模板函数模板是代表了一类函数家族家族的逻辑是一样的但是他们的类型不一样在函数传参的时候函数模板会根据实参的类型产生特定的函数。格式templatetypename T1, typename T2,......,typename Tntemplatetypename T void Swap( T left, T right) { T temp left; left right; right temp; }通过上面的模板函数就可以调用不同类型的参数的函数不需要单独实现特定类型的函数。注意typename是模板参数的关键字template是定义模板的关键字可以定义多个不同的typenametypename可以用class替代但是不可以用struct替代。函数模板的实例化隐式类型实例化编译器可以根据实参的类型自动推演传给形参的类型从而产生对应的函数。#include iostream using namespace std; template class T T Add(const T x, const T y) { return x y; } int main() { cout Add(1.1,2.2) endl;//double cout Add(1, 2) endl;//int return 0; }显式类型实例化#include iostream using namespace std; template class T T Add(const T x, const T y) { return x y; } int main() { /*cout Add(1.1,2.2) endl; cout Add(1, 2) endl;*/ int a 10; int b 3; coutAddint(a, b) endl; coutAdd(a, b) endl; return 0; }匹配规则#include iostream using namespace std; template class T T Add(const T x, const T y) { return x y; } //templateclass T1, class T2 //T1 Add(const T1 left, const T2 right) //{ //return left right; //} templateclass T T* func1(int n) { return new T[n]; } int main() { int a1 10, a2 20; double d1 10.1, d2 20.2; Add(a1, a2); Add(d1, d2); cout Add(a1, d1) endl; //由于上述模板的参数都是一样的所以该编译报错除非使用注释的代码 // 推导实例化 cout Add(a1, (int)d1) endl; cout Add((double)a1, d1) endl; //也可以强制类型转化 // 显示实例化 cout Addint(a1, d1) endl; cout Adddouble(a1, d1) endl; cout Add(a1, d1) endl;//也可以不用 double* p1 func1double(10); return 0; }类模板templatetypename T class Stack { public: Stack(int n 4) :_array(new T[n]) ,_size(0) ,_capacity(n) {} ~Stack() { delete[] _array; _array nullptr; _size _capacity 0; } void Push(const T x); private: T* _array; size_t _capacity; size_t _size; }; templateclass T//声明的时候要加上template void StackT::Push(const T x) { if (_size _capacity) { T* tmp new T[_capacity * 2]; memcpy(tmp, _array, sizeof(T) * _size); delete[] _array; _array tmp; _capacity * 2; } _array[_size] x; } int main() { // 类模板都是显示实例化 Stackint st1; // int st1.Push(1); st1.Push(2); st1.Push(3); Stackdouble st2; // double st2.Push(1.1); st2.Push(1.1); st2.Push(1.1); Stackdouble* pst new Stackdouble; //... delete pst; return 0; }注意类模板成员函数在类外声明的时候要加template函数模板实例化的时候templatetypename T T Add(T a, T b) { return a b; } // 使用时编译器能自动推导类型 Add(1, 2); // 编译器自动推导 T int Add(1.0, 2.0); // 编译器自动推导 T double类模板实例化templatetypename T class Stack { T* _data; int _top; }; // 使用类模板时必须在 中指定类型 Stackint st1; // Stackint 是类型 Stackdouble st2; // Stackdouble 是类型 Stack st3; // 错误Stack 不是类型不能直接使用总结函数模板实例化的时候编译器会自动推导不需要担心他和其他函数的冲突但是类模板实例化的时候必须要有否则报错。非类型模版参数用一个常量作为类(函数)模板的一个参数在类(函数)模板中可将该参数当成常量来使用。templateclass T, size_t N 10 class array { private: T _array[N]; // N 是编译期常量 size_t _size; }; arrayint, 20 a1; // N 20 arraydouble, 5 a2; // N 5这个是定义了一个静态数组的类如果不传参默认的空间是10。模板的特化通用模板templateclass T1, class T2 class Data { public: Data() { cout DataT1, T2 endl; } private: T1 _d1; T2 _d2; };全特化template class Dataint, char { public: Data() { cout Dataint, char endl; } }; //调用的时候 Dataint, char d2; // 走全特化直接指定什么类型才使用该函数就是给他特权单独写一个。特点template空的尖括号两个模板参数全部确定int和char匹配优先级最高偏特化templateclass T1 class DataT1, double { public: Data() { cout DataT1, double endl; } }; templateclass T1 class DataT1, char { public: Data() { cout DataT1, char endl; } }; //调用 Dataint, double d3; // 走 DataT1, double 偏特化 Datachar, double d4; // 走 DataT1, double 偏特化T1 char Datachar, char d5; // DataT1, char 偏特化 template typename T1, typename T2 class Data T1, T2 { public: Data() { cout DataT1, T2 endl; } }; //调用 Dataint, char d8; // 走 DataT1, T2 Dataint, double d9; // 走 DataT1, T2只定义一个通用的类型一个确定的类型特点第一个参数保留为T1灵活第二个参数固定为double或char匹配优先级高于通用模板低于全特化引用指针template typename T1, typename T2 class Data T1, T2* { public: Data() { cout DataT1, T2* endl; int a 0; T1 x a; // 如果 T1 intx 是 int绑定到 a T2* y a; // 如果 T2 inty 是 int*指向 a T1 z a; // 如果 T1 intz a cout typeid(x).name() endl; cout typeid(y).name() endl; } void Push(const T1 x) // 如果 T1 int参数是 const int {} }; //调用 Dataint, int* d10; 这行代码告诉编译器 第一个参数是 int引用类型 第二个参数是 int*指针类型T1本身永远是一个“普通类型”比如int、char、double它在T1这个特化版本中被组合成了一个“引用类型”int。模板的分离编译// a.h templateclass T T Add(const T left, const T right); // a.cpp templateclass T T Add(const T left, const T right) { return left right; } // main.cpp #include a.h int main() { Add(1, 2); // 链接错误找不到 Addint 的定义 }原因a.cpp编译时不知道Add会被int实例化不会生成Addint的代码main.cpp编译时看到Add的声明但不知道定义在哪里链接时找不到Addint的实现 → 报错
返回列表