初识及C++模板,总结函数模板的特点以及具体使用

简介: 初识及C++模板,总结函数模板的特点以及具体使用

模板


       我们都知道C++有一种编程思想是面向对象编程,这个在我的C++入门专栏已经系统学习过。而C++另一种编程思想就是泛型编程,主要利用的技术就是模板。


概念:模板就会通用的模具,大大提高复用性。

          例如生活中的一寸照片、PPT模板。

特点:

         模板不可以直接使用,它只是一个框架


函数模板


       C++提供两种模板机制:函数模板和类模板,今天学习函数模板

函数模板作用:

   建立一个通用函数,其函数返回值和形参类型可以不具体绑定,用户一个虚拟类型先代表

语法:


   template<typename T>

函数声明或定义:

       template --声明创建模板的关键字

       typename --表明其后面的符号是一种数据类型,可以用class关键字代替

       T:通用的数据类型,通常为字母大小写,可更换


函数模板的使用


1、自动推导,直接传入数据

2、显示指定类型(调用函数前加<数据类型>)

注意事项:


       自动推导的类型必须一致,不能一个整型一个非整型;模板必须确定出T的数据类型,才可以使用


代码演示


template<typename T>
void mySwap(T& a, T& b)
{
  T t = a;
  a = b;
  b = t;
}
void test01()
{
  int a = 10, b = 20;
  mySwap<int>(a,b);//显示
  double c = 3.4, d = 6.8;
  mySwap(c, d);//自动类型推导
  cout << "a=" << a << "b=" << b << endl;
  cout << "c=" << c << "d=" << d << endl;
}


       通过mySwap交换函数模板可以给整型和浮点型的数据进行交换,自动推导或者显示指定类型都会让T变为对应的数据类型 。自动类型推导的时候参数列表的数据类型要一致,例如:



       同样的函数模板调用,自动类型推导的方式会显示没有“与参数列表匹配的函数模板的错误”,因此使用函数模板的时候要注意这一点。


函数模板的排序案例

       趁热打铁,来一个小案例练练手吧!做一个升序排序,可以适用不同类型的数组,这里就测试整型和字符型的数组。


代码实现


//函数模板排序案例,选择排序的升序
template<class T>
void mySort(T arr[], int len)
{
  for (int i = 0; i < len - 1; i++)
  for (int j = i + 1; j < len; j++)
  {
    if (arr[j] < arr[i])
    {
    T temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
    }
  }
  cout << "升序排序成功!" << endl;
}
void test02()
{
  int arr[5] = { 2,5,3,4,1 };
  int len = sizeof(arr) / sizeof(arr[0]);
  mySort(arr, len);
  cout << "排序后数组为:" << endl;
  for (int i = 0; i < len; i++)
  {
  cout << arr[i] << " ";
  }
}
void test02q()
{
  char arr[6] = {'v','s','b','a','B','A'};
  int len = sizeof(arr) / sizeof(arr[0]);
  mySort(arr, len);
  cout << "排序后数组为:" << endl;
  for (int i = 0; i < len; i++)
  {
  cout << arr[i] << " ";
  }
}
int main(void)
{
  test02();
  cout << "\n------------" << endl;
  test02q();
}


运行效果



        这里可以看到整型和字符型的数组都能通过调用函数模板来实现升序排序


函数模板与普通函数调用规则


1、普通函数模板和普通函数都可以调用的话优先调用普通函数

2、可以通过空模板参数列表 强制调用函数模板

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

4、如果函数模板可以产生更好的匹配,优先调用函数模板


代码演示


//测试案例
void testPrint(int a)
{
  cout << "普通函数的调用" << endl;
}
template<class T>
void testPrint(T a)
{
  cout << "函数模板的调用" << endl;
}
//重载函数模板
template<class T>
void testPrint(T a,T b)
{
  cout << "重载函数模板的调用" << endl;
}
void test04()
{
  testPrint(10);
  testPrint<>(10);//空模板参数列表<>
  testPrint<>(10, 20);
  char a = 'a';


testPrint(a);/*这里理论上可以调用个普通函数以及函数模板,但是普通函数调用需要编译器隐式转换

编译器认为不如直接自动推导 T 为char数据类型,所以函数模板产生了更好的匹配,调用了函数模板*/

}


test04里的代码含义:


       第一行测试调用同一个函数名,编译器优先调用的是模板函数还是普通函数


       第二行是用空模板参数列表强制调用函数模板


       第三行是函数模板重载的调用


       下面便是一个匹配性的问题了,编译器认为自动推导比隐式转换好操作,所以优先调用函数模板


运行效果:



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


1、普通函数调用可以发生隐式类型转换

2、函数模板 用自动类型推导,不会发生隐式类型转换

3、函数模板 用显示指定类型,可以发生隐式类型转换


代码演示


//加法测试
int addTest(int a, int b)
{
  return a + b;
}
template<class T>
int addT(T a,T b)
{
  return a + b;
}
void test03()
{
  int a = 10, b = 20;
  char ch = 'A';
  cout << addTest(a, ch)<<endl;
  //cout << addT(a, ch) << endl;
  cout << addT<int>(a, ch) << endl;
}


        test03中的三个cout语句,中间的cout会出现错误,证明了函数模板和普通函数的区别


模板的局限性

       模板并不是万能的,并不是任何情况下通用性都成立


代码示例


//模板的局限性
class Person
{
public:
  Person(string name, int age)
  {
  this->name = name;
  this->age = age;
  }
  string name;
  int age;
};
//模板并不是万能的,有些特定的数据类型,需要用具体化方式做特殊实现
//对比两个数据是否相等
template<class T>
bool myCompare(T& a, T& b)
{
  if (a == b)
  {
  return true;
  }
  else
  {
  return false;
  }
}
//利用具体化Person的版本来实现代码,具体优化优先调用
template<>bool myCompare(Person& p1, Person& p2)
{
  if (p1.name == p2.name && p1.age == p2.age)
  {
  return true;
  }
  else
  {
  return false;
  }
}
void test05()
{
  int a = 10;
  int b = 20;
  bool ret = myCompare(a, b);
  if (ret)
  {
  cout << "相等" << endl;
  }
  else
  {
  cout << "不相等" << endl;
  }
}
void test06()
{
  Person p1("Tom", 10);
  Person p2("Tom", 10);
  bool ret = myCompare(p1, p2);
  if (ret)
  {
  cout << "相等" << endl;
  }
  else
  {
  cout << "不相等" << endl;
  }
}
int main(void)
{
  test05();
  test06();
  return 0;
}
template<class T>
bool myCompare(T& a, T& b)


以上两行代码是声明用来比较两个数据是否相等的函数模板。


然而对于自定义类型的数据,比如类,利用上面的函数模板肯定无法达到预期效果。所以要对模板进行具体化操作:


template<>bool myCompare(Person& p1, Person& p2)


利用具体化Person的版本来实现代码,具体优化优先调用,编译器检测到函数参数是类对象,就会自动调用这个具体化后的函数模板,完成数据比较操作。


运行效果:




目录
打赏
0
0
0
0
88
分享
相关文章
模板(C++)
本内容主要讲解了C++中的函数模板与类模板。函数模板是一个与类型无关的函数家族,使用时根据实参类型生成特定版本,其定义可用`typename`或`class`作为关键字。函数模板实例化分为隐式和显式,前者由编译器推导类型,后者手动指定类型。同时,非模板函数优先于同名模板函数调用,且模板函数不支持自动类型转换。类模板则通过在类名后加`&lt;&gt;`指定类型实例化,生成具体类。最后,语录鼓励大家继续努力,技术不断进步!
|
1月前
|
【c++】继承(继承的定义格式、赋值兼容转换、多继承、派生类默认成员函数规则、继承与友元、继承与静态成员)
本文深入探讨了C++中的继承机制,作为面向对象编程(OOP)的核心特性之一。继承通过允许派生类扩展基类的属性和方法,极大促进了代码复用,增强了代码的可维护性和可扩展性。文章详细介绍了继承的基本概念、定义格式、继承方式(public、protected、private)、赋值兼容转换、作用域问题、默认成员函数规则、继承与友元、静态成员、多继承及菱形继承问题,并对比了继承与组合的优缺点。最后总结指出,虽然继承提高了代码灵活性和复用率,但也带来了耦合度高的问题,建议在“has-a”和“is-a”关系同时存在时优先使用组合。
122 6
㉿㉿㉿c++模板的初阶(通俗易懂简化版)㉿㉿㉿
㉿㉿㉿c++模板的初阶(通俗易懂简化版)㉿㉿㉿
|
2月前
|
【c++】模板详解(2)
本文深入探讨了C++模板的高级特性,包括非类型模板参数、模板特化和模板分离编译。通过具体代码示例,详细讲解了非类型参数的应用场景及其限制,函数模板和类模板的特化方式,以及分离编译时可能出现的链接错误及解决方案。最后总结了模板的优点如提高代码复用性和类型安全,以及缺点如增加编译时间和代码复杂度。通过本文的学习,读者可以进一步加深对C++模板的理解并灵活应用于实际编程中。
43 0
深入理解C++模板编程:从基础到进阶
在C++编程中,模板是实现泛型编程的关键工具。模板使得代码能够适用于不同的数据类型,极大地提升了代码复用性、灵活性和可维护性。本文将深入探讨模板编程的基础知识,包括函数模板和类模板的定义、使用、以及它们的实例化和匹配规则。
【C++11】可变模板参数详解
本文详细介绍了C++11引入的可变模板参数,这是一种允许模板接受任意数量和类型参数的强大工具。文章从基本概念入手,讲解了可变模板参数的语法、参数包的展开方法,以及如何结合递归调用、折叠表达式等技术实现高效编程。通过具体示例,如打印任意数量参数、类型安全的`printf`替代方案等,展示了其在实际开发中的应用。最后,文章讨论了性能优化策略和常见问题,帮助读者更好地理解和使用这一高级C++特性。
183 4
【C++】模板详细讲解(含反向迭代器)
C++模板是泛型编程的核心,允许编写与类型无关的代码,提高代码复用性和灵活性。模板分为函数模板和类模板,支持隐式和显式实例化,以及特化(全特化和偏特化)。C++标准库广泛使用模板,如容器、迭代器、算法和函数对象等,以支持高效、灵活的编程。反向迭代器通过对正向迭代器的封装,实现了逆序遍历的功能。
74 3
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
5月前
|
【c++】模板详解(1)
本文介绍了C++中的模板概念,包括函数模板和类模板,强调了模板作为泛型编程基础的重要性。函数模板允许创建类型无关的函数,类模板则能根据不同的类型生成不同的类。文章通过具体示例详细解释了模板的定义、实例化及匹配原则,帮助读者理解模板机制,为学习STL打下基础。
69 0
【C++打怪之路Lv7】-- 模板初阶
【C++打怪之路Lv7】-- 模板初阶
54 1

热门文章

最新文章

AI助理

你好,我是AI助理

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