第八层:模板(上)

简介: 第八层:模板(上)

前情回顾


在上一层中,我遇到了面向对象的最后一个特性——多态,使用多态可以让代码组织结构更加情绪,使可读性变强,利于程序的前期和后期的扩展和维护,掌握多态之后,面向对象结束了, 后面会是什么呢…


🚄上章地址:第七层:多态


模板


上到了第八层,映入眼帘的是一个巨大的石碑,“你来了,在C++中,除了面向过程编程和面向对象编程以外,还有一种编程思想,叫做泛型编程,泛型编程主要通过模板实现,这层就需要你掌握模板的力量…"。


模板的概念


模板就是建立一个通用的模具,大大提高复用性,比如PPT模板、空白的学生证,这些东西都有一些特点,不能直接使用,需要使用者去添加一些东西,而且不是通用的,比如这个PPT模板是做年度总结的,那就不能强套到一些和年度总结不着边的东西上,因此可以总结出模板的特点。


模板的特点


1.模板只是一个框架

2.这个框架不是万能的


模板分类


在C++中模板分为两类:


函数模板

类模板


函数模板


作用


建立一个通用函数,其函数的返回类型和形参可以不具体制定,用一个虚拟的类型来代表


语法


函数模板的语法为:


templatte< typename T>

函数的声明或者定义

解释:


template:声明创建函数模板

typename:表明其后面的符号是一种通用的数据类型,可以用class替代。

T:通用的数据类型,可以替换成别的字母

可以尝试写一个函数模板:


#include<iostream>
using namespace std;
template<typename T>
void print(T a)
{
  cout << a << endl;
}
int main()
{
  return 0;
}

0a2653c851af460fa595bd959398a8f1.png

可以正常跑起来,那函数模板怎么使用呢?


函数模板的使用


1.自动类型推导:直接传入类型,让编译器自己识别是什么类型

2.显示制定类型:告诉编译器是什么类型,语法如下:

函数名< 是什么数据类型 >(参数)

验证一下两种使用方法:


自动类型推导

#include<iostream>
using namespace std;
template<typename T>
void print(T a)
{
  cout << a << endl;
}
void test1()
{
  print(1);
}
int main()
{
  test1();
  return 0;
}

0eacb84100b54626af849e6b562bf92a.png

显示指定类型

#include<iostream>
using namespace std;
template<typename T>
void print(T a)
{
  cout << a << endl;
}
void test1()
{
  print<int>(1);
}
int main()
{
  test1();
  return 0;
}

2d65d23f6d4748949b924e4057485923.png

注意事项

1.自动类型推导必须推导出一致的数据类型才可以使用

2.模板必须确定出T的数据类型,才可以使用

第一点解释:


#include<iostream>
using namespace std;
template<typename T>
void print(T a,T b)
{
  cout << a << endl;
}
void test1()
{
  int a = 0;
  char b = 0;
  print(a,b);
}
int main()
{
  test1();
  return 0;
}

2e9b90b2ca334476abebe75bafe6eeaa.png

可以看到,一个int的类型和一个char类型的数据,两个类型就不一致,这个时候,T不知道自己应该是什么,所以报错,说明对于自动类型推导就需要让两个类型一致,那显示指定类型呢?


#include<iostream>
using namespace std;
template<typename T>
void print(T a,T b)
{
  cout << a << b << endl;
}
void test1()
{
  int a = 0;
  char b = 0;
  print<int>(a,b);
}
int main()
{
  test1();
  return 0;
}

4cebaac233b3433da32a72337a77fc60.png

显示指定类型就可以使用。


第二点解释:

当函数模板没有参数的时候,可以直接调用吗?


#include<iostream>
using namespace std;
template<typename T>
void print()
{
  cout << "hello world" << endl;
}
void test1()
{
  print();
}
int main()
{
  test1();
  return 0;
}

6de278e6d6694ce5bb08e7e842b7e74b.png

是不可以直接调用的,因为使用函数模板时,必须人编译器知道通用数据类型是什么,就算没有参数,也需要,这个时候可采用显示指定类型,不管是什么类型,都能跑去来:


#include<iostream>
using namespace std;
template<typename T>
void print()
{
  cout << "hello world" << endl;
}
void test1()
{
  print<int>();
  print<char>();
  print<double>();
}
int main()
{
  test1();
  return 0;
}

7a399525ddec4b77923c464820b33738 (1).png


普通函数和函数模板的区别


普通函数调用可以发生自动类型转换(隐式类型转换)

函数模板在调用时,如果利用自动类型推导,不会发生隐式类型转换

如果利用显示指定类型,可以发生隐式类型转换

普通函数:


#include<iostream>
using namespace std;
int Swap(int a, int b)
{
  return a + b;
}
void test1()
{
  int a = 20;
  char b = '1';
  int c=Swap(a, b);
  cout << c << endl;
}
int main()
{
  test1();
  return 0;
}

7a399525ddec4b77923c464820b33738.png

c是69,这是因为发生了隐式类型转换,char转换成了int,同时这是字符1的ASCII码值为49,49加20,就是69。

函数模板:

自动类型推导在上面的注意事项说到,必须推导出统一的数据类型才能跑起来,所以这个时候传两个类型不同的一定是会报错的,就不进行验证了,这个时候试着用显示指定类型试试:


#include<iostream>
using namespace std;
template<typename T>
int Swap(T a, T b)
{
  return a + b;
}
void test1()
{
  int a = 20;
  char b = '1';
  int c=Swap<int>(a, b);
  cout << c << endl;
}
int main()
{
  test1();
  return 0;
}


0a2653c851af460fa595bd959398a8f1.png

0a2653c851af460fa595bd959398a8f1.png

这个时候,编译器会将参数内的所有数视为int类型的,就发生了隐式类型转换。


普通函数和函数模板的调用规则


1.如果函数模板和普通函数都可以实现时,优先调用普通函数

2.可以通过空模板参数来强调函数模板,让使用函数模板

3.函数模板可以发生重载

4。如果函数模板可以产生更好的匹配,就使用函数模板


优先调用普通函数


#include<iostream>
using namespace std;
template<typename T>
int Add(T a, T b)
{
  cout << "函数模板调用" << endl;
  return a + b;
}
int Add(int a, int b)
{
  cout << "普通函数调用" << endl;
  return a + b;
}
void test1()
{
  int a = 20;
  int b = 20;
  int c=Add(a, b);
  cout << c << endl;
}
int main()
{
  test1();
  return 0;
}

0eacb84100b54626af849e6b562bf92a.png

可以发现两个函数实现内容相同,但是优先调用的普通函数。


空模板强调函数模板


空模板的语法:函数名<>(传参)

#include<iostream>
using namespace std;
template<typename T>
int Add(T a, T b)
{
  cout << "函数模板调用" << endl;
  return a + b;
}
int Add(int a, int b)
{
  cout << "普通函数调用" << endl;
  return a + b;
}
void test1()
{
  int a = 20;
  int b= 20;
  int c=Add<>(a, b);
  cout << c << endl;
}
int main()
{
  test1();
  return 0;
}

2d65d23f6d4748949b924e4057485923.png

这个时候就调用了函数模板了,就是空模板起的作用,可以强制调用模板。


函数模板可以发生重载


#include<iostream>
using namespace std;
template<typename T>
int Add(T a, T b)
{
  return a + b;
}
template<typename T>
int Add(T a, T b, T c)
{
  return a + b + c;
}
void test1()
{
  int a = 20;
  int b= 20;
  int c = 20;
  int d = Add<>(a, b, c);
  cout << d << endl;
}
int main()
{
  test1();
  return 0;
}


2e9b90b2ca334476abebe75bafe6eeaa.png

2e9b90b2ca334476abebe75bafe6eeaa.png

相关文章
|
6月前
|
算法 程序员 编译器
【C++】—— 模板介绍
【C++】—— 模板介绍
|
6月前
树链剖分模板
树链剖分模板
47 0
|
4月前
|
存储 编译器 C++
【C++】详解C++的模板
【C++】详解C++的模板
|
5月前
|
Python
模板
【6月更文挑战第29天】模板。
26 2
|
6月前
|
存储 编译器 C++
|
6月前
|
Ubuntu Java Docker
Dockfile应用模板
Dockfile应用模板
96 0
|
6月前
|
算法 C++ 容器
|
算法
The Suspects (并查集问题模板)
The Suspects (并查集问题模板)
50 0
|
编译器 C++
模板(C++)
模板(C++)
68 0