【C++基础(十)】C++泛型编程--模板初阶

简介: 【C++基础(十)】C++泛型编程--模板初阶

1. 前言

在学习数据结构时会遇见以下的情况

数据结构中存储的类型往往不能确定

所以在实现数据结构时往往是这样做的

typedef int DateType

在写代码时用DateType来表示类型
如果想存储浮点型只需将int改为float

但是这样写会遇见一个问题:

写好数据结构类后在创建对象时

此.cpp文件只能创建一种类型的对象

对象存储的全是int/char/double类型

不能同时创建存储int的和char的对象

Data d1;//存储的int类型
Date d2;//存储的char类型

泛型编程:
编写与类型无关的通用代码
是代码复用的一种手段
模板是泛型编程的基础

本章重点:

本篇文章重点讲解函数模板
和类模板的使用以及特性


2. 函数模板

请看以下函数代码:

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;
}

这样写非常的麻烦

使用模板可以使代码通用于不同类型:

swap函数模板:

template<typename T>
void Swap( T& left, T& right)
{
  T temp = left;
  left = right;
  right = temp;
}

写好上面的代码后,传int类型进去
T就会被实例化为int,以此类推

template和typename是规定
好了必须这样写,T是自己取的名字
其中,typename可以用class替换
并且一次性可以定义多个类型:

template<class T1,typename T2,class T3>

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);
 }

第一次调用的T被推演为int类型
第二粗调用的T被推演为double

不能这样写代码:

Add(a1, d1);

系统根据a1推演出T是int类型
但是d1是double类型不能用int
类型的参数啦接受,所以会报错


  1. 显示实例化

在函数名后的<>中指定模板参数的类型

int main(void)
{
 int a = 10;
 double b = 20.0;
 
 // 显式实例化
 Add<int>(a, b);
 return 0;
}

如果类型不匹配
编译器会尝试进行隐式类型转换
若无法转换成功编译器将会报错


5. 函数模板参数的匹配规则

模板函数和普通函数可以同时存在:

// 专门处理int的加法函数
int Add(int left, int right)
{
  return left + right;
}
// 通用加法函数
template<class T>
T Add(T left, T right)
{
  return left + right;
}

在调用函数时若参数和非模板函数匹配
那么编译器会优先调用非模板函数
若非模板函数不匹配或模板函数更匹配
那么编译器会优先调用模板函数

Add(10,20)//调用非模板
Add(11.1,6.3);//调用模板

6. 类模板

类模板的应用非常广泛

像开头提到的数据结构问题

类模板的定义格式:

template<class T1, class T2, ..., class Tn>
class example
{
 // 类内成员定义
};

和函数模板类似,类模板也可以同时

定义多个模板参数

写一个简易的顺序表:

template<class T>
class Vector
{ 
public :
 Vector(size_t capacity = 10)
 : _Data(new T[capacity])
 , _size(0)
 , _capacity(capacity)
 {}
 T& operator[](size_t pos)
 {
   assert(pos < _size);
   return _Data[pos];
 }
 
private:
 T* _Data;
 size_t _size;
 size_t _capacity;
};

所有实际类型需要出现的地方用T代替


7. 类模板的实例化

和函数模板不同,类模板没有隐式推演
用户必须显示实例化

Vector<int> v1;

注意:
Vector是类名
Vector< int >才是类型

当在类中声明一个函数
但是想在类外定义时
若函数的参数或内部使用的类型
和模板有关系,那么必须这样写:

template<class T>
class Vector
{ 
public :
    //类中声明函数
  void push_back(T x);
private:
 T* _Data;
 size_t _size;
 size_t _capacity;
};

类外定义:

template<class T>
void Vector<T>::push_back(T x)
{
  _Date[_size] = x;
  _size++;
}

注:必须要再加上类模板template

并且要指定类域


8. 总结以及拓展

泛型编程是C++的一大利器

它极大的减少了代码的复杂程度

并且增加了代码的可读性

C++基础部分的内容已经全部结束
下一阶段进入C++中阶:STL的使用

拓展:

泛型编程拓展阅读


🔎 下期预告:STL库的介绍以及使用 🔍


目录
打赏
0
1
1
0
18
分享
相关文章
4步实现C++插件化编程,轻松实现功能定制与扩展(2)
本文是《4步实现C++插件化编程》的延伸,重点介绍了新增的插件“热拔插”功能。通过`inotify`接口监控指定路径下的文件变动,结合`epoll`实现非阻塞监听,动态加载或卸载插件。核心设计包括`SprDirWatch`工具类封装`inotify`,以及`PluginManager`管理插件生命周期。验证部分展示了插件加载与卸载的日志及模块状态,确保功能稳定可靠。优化过程中解决了动态链接库句柄泄露问题,强调了采纳用户建议的重要性。
65 13
4步实现C++插件化编程,轻松实现功能定制与扩展(2)
模板(C++)
本内容主要讲解了C++中的函数模板与类模板。函数模板是一个与类型无关的函数家族,使用时根据实参类型生成特定版本,其定义可用`typename`或`class`作为关键字。函数模板实例化分为隐式和显式,前者由编译器推导类型,后者手动指定类型。同时,非模板函数优先于同名模板函数调用,且模板函数不支持自动类型转换。类模板则通过在类名后加`&lt;&gt;`指定类型实例化,生成具体类。最后,语录鼓励大家继续努力,技术不断进步!
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
C++ 标准模板库(STL)提供了一组功能强大的容器类,用于存储和操作数据集合。不同的容器具有独特的特性和应用场景,因此选择合适的容器对于程序的性能和代码的可读性至关重要。对于刚接触 C++ 的开发者来说,了解这些容器的基础知识以及它们的特点是迈向高效编程的重要一步。本文将详细介绍 C++ 常用的容器,包括序列容器(`std::vector`、`std::array`、`std::list`、`std::deque`)、关联容器(`std::set`、`std::map`)和无序容器(`std::unordered_set`、`std::unordered_map`),全面解析它们的特点、用法
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
㉿㉿㉿c++模板的初阶(通俗易懂简化版)㉿㉿㉿
㉿㉿㉿c++模板的初阶(通俗易懂简化版)㉿㉿㉿
|
2月前
|
【c++】模板详解(2)
本文深入探讨了C++模板的高级特性,包括非类型模板参数、模板特化和模板分离编译。通过具体代码示例,详细讲解了非类型参数的应用场景及其限制,函数模板和类模板的特化方式,以及分离编译时可能出现的链接错误及解决方案。最后总结了模板的优点如提高代码复用性和类型安全,以及缺点如增加编译时间和代码复杂度。通过本文的学习,读者可以进一步加深对C++模板的理解并灵活应用于实际编程中。
43 0
深入浅出 C++ STL:解锁高效编程的秘密武器
C++ 标准模板库(STL)是现代 C++ 的核心部分之一,为开发者提供了丰富的预定义数据结构和算法,极大地提升了编程效率和代码的可读性。理解和掌握 STL 对于 C++ 开发者来说至关重要。以下是对 STL 的详细介绍,涵盖其基础知识、发展历史、核心组件、重要性和学习方法。
深入理解C++模板编程:从基础到进阶
在C++编程中,模板是实现泛型编程的关键工具。模板使得代码能够适用于不同的数据类型,极大地提升了代码复用性、灵活性和可维护性。本文将深入探讨模板编程的基础知识,包括函数模板和类模板的定义、使用、以及它们的实例化和匹配规则。
【C++11】可变模板参数详解
本文详细介绍了C++11引入的可变模板参数,这是一种允许模板接受任意数量和类型参数的强大工具。文章从基本概念入手,讲解了可变模板参数的语法、参数包的展开方法,以及如何结合递归调用、折叠表达式等技术实现高效编程。通过具体示例,如打印任意数量参数、类型安全的`printf`替代方案等,展示了其在实际开发中的应用。最后,文章讨论了性能优化策略和常见问题,帮助读者更好地理解和使用这一高级C++特性。
182 4
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等