c++模板的简单认识

简介: c++模板的简单认识

前言



ADD函数很好写,但是如果我们要有int类型的,double类型的,char类型的等等各种类型,难道要写这么多不同的ADD函数吗,这么写简直太麻烦了,所以有了泛型编程的概念。


一、泛型编程



实现一个通用的ADD函数有很多办法,就比如函数重载,但是函数重载又有很多的缺点,比如:

1.重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数。

2.代码的可维护性比较低,一个出错可能所有的重载都出错。

那能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生产代码呢?

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


函数模板


函数模板的概念:函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。


函数模板格式:

template<typename p1,typename p2........>

注意:typename用来定义模板参数 关键字也可以使用class(切记:不能使用struct代替class)

template <class T>
void Swap(T& d1, T& d2)
{
  T tmp = d1;
  d1 = d2;
  d2 = tmp;
}
int main()
{
  int a = 10, b = 50;
  Swap(a, b);
  double c = 2.36, d = 6.15;
  Swap(c, d);
  return 0;
}


3b40aac6911a4438bf22fb7ba793e11c.png

那么上图中的两次调用Swap函数是同一个函数吗?这里不是同一个函数,我们先来验证一下:

2a078b1112d14e37b9b44383c42af471.png

f3a3c429bf594036a65ca23a55f30a33.pngf3a3c429bf594036a65ca23a55f30a33.png


通过汇编代码我们发现两个函数并不是同一个,他们有着不同的地址。这是因为模板就像是印刷的模具一样,生成的函数就是印刷出来的书,我们看的是书并不是印刷的板,每本书用的印刷的板都是一样的但是书中的内容是不一样的。

函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模 板就是将本来应该我们做的重复的事情交给了编译器。

e10acf4bb36241c9b20e04ae82d91700.png

下面我们来看一些关于模板的小细节:

template<class T>
T Add(const T& left, const T& right)
{
  return left + right;
}
int main()
{
  int a1 = 10, a2 = 20;
  double d1 = 10.22, d2 = 20.32;
  cout << Add(a1, a2) << endl;
  cout << Add(d1, d2) << endl;
  return 0;
}


首先上面的代码是可以正常编译的,那么如果写成下面这样呢?

6e2c58f90b304e4fa0c50c06917a0a23.png

这里有两种解决方式,一种是强制类型转换,一种是显式实例化。

int main()
{
  int a1 = 10, a2 = 20;
  double d1 = 10.22, d2 = 20.32;
  //实参传递给形参,自动推演模板类型
  cout << Add(a1, (int)d1) << endl;
  cout << Add(d1, d2) << endl;
  //显示实例化
  cout << Add<int>(a1, d2) << endl;
  cout << Add<double>(a1, d1) << endl;
  return 0;
}


ebf3f3fbd892496faaa16a9d6b77c830.png

在函数名后加<(需要的类型)>就可以完成显式实例化,编译器直接以显式的类型去计算。


模板参数的匹配原则


// 专门处理int的加法函数
int Add(int left, int right)
{
  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版本
}
int main()
{
  Test();
  return 0;
}

87d7c08fce4b43aeb6f5d2d9b3e91c6a.png

我们可以看到上面代码中有两个Add函数,当他们类型都为int的时候为什么没有函数重定义呢?

这是因为一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。

586ed4cd9714418d81e70ccdb1c85a89.png


那么像上图这样的情况编译器会调用哪个呢?答案是第一个,因为对于非模板函数和同名函数模板,如果其他条件都相同,在调用时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的一个函数,那么将选择模板。

什么意思呢?就是说已经存在一个能用的函数了编译器就不会花时间去实例化一个相同的函数,而是调用那个已经存在的函数。

如果我们必须要调用那个模板有什么方法吗?

caced6abeec24b7f9107748a648f8010.png

我们直接在函数名后显示实例化就会调用模板了。


类模板

template<class T>
class Stack
{
public:
  Stack(int capacity = 4)
  {
    _a = new T[capacity];
    _top = 0;
    _capacity = capacity;
  }
  ~Stack()
  {
    delete[] _a;
    _a = nullptr;
    _top = _capacity = 0;
  }
paivate:
  T* _a;
  size_t _top;
  size_t _capacity;
};
int main()
{
  Stack<int> sl;
  Stack<double> st;
  return 0;
}

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。

注意:模板的声明和定义分开与普通类不一样,如下图:

b832acdbfdc040a6bff91e7d6e533c99.png

9cb58e09c3074b2d85fc4be48a85c823.png

模板的声明和定义分离只限于在一个文件中,如果声明和定义在两个不同的文件会出现链接错误。

0472bfbf0be34f47922594518edffe59.png

模板的类创建对象必须显示实例化在类名后面加<>确定其类型。


总结



模板的出现让我们在写一些代码相同但是类型不同的函数或者类的时候方便了很多,以前这些都是由我们自己写出来的,有了模板就可以由编译器去做这件事,并且编译器做的比我们更好,因为人写总是会出现一些粗心的错误,编译器却不会。


目录
相关文章
|
5天前
|
编译器 C语言 C++
从C语言到C++_21(模板进阶+array)+相关笔试题(下)
从C语言到C++_21(模板进阶+array)+相关笔试题
19 2
|
5天前
|
编译器 C语言 C++
从C语言到C++_21(模板进阶+array)+相关笔试题(上)
从C语言到C++_21(模板进阶+array)+相关笔试题
17 0
|
9天前
|
存储 算法 C++
高效利用C++ STL库:标准模板库的使用技巧
本文介绍了C++ STL(标准模板库)的高效使用技巧,包括选择合适的容器类型、使用`emplace_back`而非`push_back`、预分配容器空间和范围for循环遍历容器。此外,还讨论了STL算法的运用,如用算法替代手动循环、使用lambda表达式和进行容器操作。通过这些技巧,开发者可以提升C++代码的性能和可读性。
|
9天前
|
程序员 编译器 C++
C++中的模板与泛型编程技术深度解析
C++中的模板与泛型编程技术深度解析
|
9天前
|
存储 算法 程序员
C++模板编程与泛型技术探秘
这篇文章探讨了C++中的模板编程和泛型技术,这两种技术增强了代码复用和抽象能力。文章介绍了函数模板和类模板的概念,通过示例展示了如何定义和使用它们。泛型技术是一种编程范式,强调编写与类型无关的代码,提高代码复用性和灵活性。C++11后的版本通过类型萃取和变长模板参数进一步扩展了模板功能。模板和泛型广泛应用在数据结构、算法、库和框架的开发中,如STL。掌握这些技术有助于编写更高效、灵活的代码,并推动软件开发的创新和进步。
|
12天前
|
编译器 C++
【C++】模板进阶 -- 详解
【C++】模板进阶 -- 详解
|
12天前
|
编译器 C++ 容器
C++模板的原理及使用
C++模板的原理及使用
|
12天前
|
编译器 程序员 C语言
【C++】模板初阶 -- 详解
【C++】模板初阶 -- 详解
|
12天前
|
算法 编译器 C语言
从C语言到C++⑩(第四章_模板初阶+STL简介)如何学习STL(下)
从C语言到C++⑩(第四章_模板初阶+STL简介)如何学习STL
21 0
|
12天前
|
编译器 C语言 C++
从C语言到C++⑩(第四章_模板初阶+STL简介)如何学习STL(上)
从C语言到C++⑩(第四章_模板初阶+STL简介)如何学习STL
11 0