C++泛型编程基本概念详解

C++泛型编程基本概念详解,博智网带你了解详细信息 。
目录

  • 1.什么是泛型编程?
  • 2.函数模板
    • (1)函数模板概念
    • (2)函数模板格式
    • (3)函数模板的原理
    • (4)函数模板的实例化
    • (5)模板参数的匹配原则
  • 3.类模板
    • (1)类模板的定义格式
    • (2)类模板的实例化
  • 总结

    1.什么是泛型编程?比如说 , 我们如何实现一个通用的交换函数呢?int型、double型、char型的交换
    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;}......
    虽然我们可以使用函数重载来实现 , 但是有一下几个不好的地方:
    (1)重载的函数仅仅只是类型不同 , 代码的复用率比较低 , 当新类型出现时 , 就需要增加对应的函数 。
    (2)代码的可维护性比较低 , 一个出错可能所有的重载均出错 。
    泛型编程:编写与类型无关的通用代码 , 是代码复用的一种手段 。
    模板是泛型编程的基础 。包括函数模板和类模板 。
    前面我们介绍的vector,list,map都是一种数据结构容器 , 
    容器本身的存储结构不同 , 各容器中存在的数据类型也可以不同 。
    但我们在访问这些容器中数据时 , 拥有相同的方式 。
    这种方式就叫做“泛型编程” , 顾名思义 , 不同的类型采用相同的方式来操作 。
    2.函数模板
    (1)函数模板概念函数模板代表了一个函数家族 , 该函数模板与类型无关 , 在使用时被参数化 , 根据实参类型产生函数的特定类型版本 。
    (2)函数模板格式template<typename T1, typename T2,......,typename Tn>返回值类型 函数名(参数列表){}//typename是用来定义模板参数关键字 , 也可以使用class(切记:不能使用struct代替class)
    template<typename T>void Swap(T& left , T& right){ T temp = left; left = right; right = temp;}
    (3)函数模板的原理函数模板是一个蓝图 , 它本身并不是函数 , 是编译器通过使用方式产生特定具体类型函数的模具 。所以其实模板就是将本来应该我们做的重复的事情交给了编译器 。
    在编译器编译阶段 , 对于函数模板的使用 , 编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用 。比如:当用double类型使用函数模板时 , 编译器通过对实参类型的推演 , 将T确定为double类型 , 然后产生一份专门处理double类型的代码 , 对于字符类型也是如此 。
    (4)函数模板的实例化用不同类型的参数使用函数模板时 , 称为函数模板的实例化 。
    模板参数实例化分为:隐式实例化和显式实例化 。
    1)隐式实例化:让编译器根据实参推演模板参数的实际类型
    template<class T>T Add(const T& left, const T& right){ return left + right;}int main(){ int a1 = 10, a2 = 20; double d1 = 10.0, d2 = 20.0; Add(a1, a2); Add(d1, d2);/*Add(a1, d1);该语句不能通过编译 , 因为在编译期间 , 当编译器看到该实例化时 , 需要推演其实参类型通过实参a1将T推演为int , 通过实参d1将T推演为double类型 , 但模板参数列表中只有一个T , 编译器无法确定此处到底该将T确定为int 或者 double类型而报错注意:在模板中 , 编译器一般不会进行类型转换操作 , 因为一旦转化出问题 , 编译器就需要背黑锅*/// 此时有两种处理方式:1. 用户自己来强制转化 2. 使用显式实例化Add(a1, (int)d1);return 0;}
    2)显式实例化:在函数名后的<>中指定模板参数的实际类型
    int main(void){ int a = 10; double b = 20.0; // 显式实例化 Add<int>(a, b); return 0; //如果类型不匹配 , 编译器会尝试进行隐式类型转换 , 如果无法转换成功编译器将会报错 。}
    (5)模板参数的匹配原则1)一个非模板函数可以和一个同名的模板函数同时存在 , 而且该函数模板还可以被实例化为这个非模板函数 。
    int Add(int left, int right)// 专门处理int的加法函数{ return left + right;}template<class T>// 通用加法函数T Add(T left, T right){ return left + right;}void Test(){ Add(1, 2); // 与非模板函数匹配 , 编译器不需要特化 Add<int>(1, 2); // 调用编译器特化的Add版本}

    推荐阅读