C++ Tutorials: C++ Language: Program structure: Overloads and templates

本文介绍了C++中的函数重载和模板。函数重载允许在同一个作用域内有相同名称但参数不同的函数,编译器通过实参类型来决定调用哪个函数。函数模板则提供了泛型编程的能力,允许创建适用于多种类型的函数,编译器会根据实参类型自动实例化模板。模板可以有类型和非类型参数,并且模板参数可以推断,简化了代码的使用。
摘要由CSDN通过智能技术生成

C++官方参考链接:Overloads and templates - C++ Tutorials (cplusplus.com)

重载函数
在C++中,如果形参不同,两个不同的函数可以有相同的名称;要么是因为它们有不同数量的形参,要么是因为它们的任何形参是不同类型的。
例如:
// overloading functions
#include <iostream>
using namespace std;

int operate (int a, int b)
{
  return (a*b);
}

double operate (double a, double b)
{
  return (a/b);
}

int main ()
{
  int x=5,y=2;
  double n=5.0,m=2.0;
  cout << operate (x,y) << '\n';
  cout << operate (n,m) << '\n';
  return 0;

输出 

在本例中,有两个名为operate的函数,但其中一个函数有两个int类型的形参,而另一个函数有两个double类型的形参。编译器通过检查调用函数时作为实参传递的类型,知道在每种情况下调用哪一个。如果带有两个int实参调用它,则调用带有两个int形参的函数;如果带有两个double实参调用它,则调用带有两个double形参的函数。
在本例中,两个函数的行为完全不同,int版本的函数乘以它的实参,而double版本的函数除以它的实参。这通常不是一个好主意。两个具有相同名称的函数通常被期望具有---至少---类似的行为,但是这个示例说明它们完全有可能不具有类似的行为。两个重载函数(即名称相同的两个函数)具有完全不同的定义;它们是不同的函数,只是碰巧有相同的名称。
注意,函数不能仅按其返回类型重载。它的至少一个形参必须具有不同的类型。

函数模板
重载的函数可能具有相同的定义。例如: 
// overloaded functions
#include <iostream>
using namespace std;

int sum (int a, int b)
{
  return a+b;
}

double sum (double a, double b)
{
  return a+b;
}

int main ()
{
  cout << sum (10,20) << '\n';
  cout << sum (1.0,1.5) << '\n';
  return 0;
}

这里,sum使用不同的形参类型重载,但具有完全相同的函数体。
对于许多类型,函数sum可以重载,并且所有类型具有相同的函数体是有意义的。对于这样的情况,C++能够用泛型类型定义函数,称为函数模板。定义一个函数模板遵循与普通函数相同的语法,除了它前面有template关键字和一系列用尖括号<>括起来的模板形参:
template <template-parameters> function-declaration

模板形参由逗号分隔的一系列形参组成。通过指定class或typename关键字后接标识符,这些形参可以是泛型模板类型。然后可以在函数声明中使用该标识符,就像它是一个普通类型一样。例如,一个泛型的sum函数可以定义为: 
template <class SomeType>
SomeType sum (SomeType a, SomeType b)
{
  return a+b;
}
泛型类型是在模板实参列表中用关键字class指定的还是用关键字typename指定的没有区别(它们在模板声明中是100%的同义词)。
在上面的代码中,声明SomeType(尖括号括起来的模板形参中的泛型类型)允许SomeType在函数定义中的任何地方使用,就像任何其他类型一样;它可以用作形参的类型,返回类型或声明此类型的新变量。在所有情况下,它都表示在模板实例化时确定的泛型类型。
实例化模板是将模板应用于使用模板形参的特定类型或值创建函数。这是通过调用函数模板来完成的,使用与调用普通函数相同的语法,但指定用尖括号括起来的模板实参:
name <template-arguments> (function-arguments) 

例如,上面定义的sum函数模板可以用:
x = sum<int>(10,20); 
函数sum<int>只是函数模板sum的可能实例之一。在这种情况下,通过在调用中使用int作为模板实参,编译器自动实例化sum的一个版本,其中SomeType的每次出现都被int替换,就像它被定义为:
int sum (int a, int b)
{
  return a+b;
}
让我们看一个实际的例子:
// function template
#include <iostream>
using namespace std;

template <class T>
T sum (T a, T b)
{
  T result;
  result = a + b;
  return result;
}

int main () {
  int i=5, j=6, k;
  double f=2.0, g=0.5, h;
  k=sum<int>(i,j);
  h=sum<double>(f,g);
  cout << k << '\n';
  cout << h << '\n';
  return 0;

在本例中,我们使用T作为模板形参名,而不是SomeType。它没有区别,T实际上是泛型类型的一个非常常见的模板形参名称。
在上面的例子中,我们两次使用了函数模板sum。第一次使用int类型的实参,第二次使用double类型的实参。编译器每次都实例化并调用函数的适当版本。
注意T也被用来在sum中声明该(泛型)类型的局部变量:
T result;
因此,result将是一个与形参a和b的类型相同的变量,也是函数返回的类型。
在这种使用泛型类型T作为sum形参的特定情况下,编译器甚至可以自动推断数据类型,而不必在尖括号中显式指定数据类型。因此,与其显式指定模板实参,不如使用:
k = sum<int> (i,j);
h = sum<double> (f,g);
也可以简单地写成:
k = sum (i,j);
h = sum (f,g);
没有用尖括号括起的类型。因此,类型自然应该是明确的。如果调用sum时带不同类型的实参,编译器可能无法自动推断T的类型。
模板是一个功能强大的多功能特性。它们可以有多个模板形参,函数仍然可以使用普通的非模板类型。例如:
// function templates
#include <iostream>
using namespace std;

template <class T, class U>
bool are_equal (T a, U b)
{
  return (a==b);
}

int main ()
{
  if (are_equal(10,10.0))
    cout << "x and y are equal\n";
  else
    cout << "x and y are not equal\n";
  return 0;
}

注意,这个例子在调用are_equal时使用了自动模板形参推断:
are_equal(10,10.0)
等价于:
are_equal<int,double>(10,10.0)
不可能有歧义,因为数值字面量总是具有特定的类型:除非用后缀特别指定,整数字面量总是产生int类型的值,而浮点字面量总是产生double类型的值。因此,10总是int类型,10.0总是double类型。

非类型模板实参
模板形参不仅可以包括由class或typename引入的类型,还可以包括特定类型的表达式:
// template arguments
#include <iostream>
using namespace std;

template <class T, int N>
T fixed_multiply (T val)
{
  return val * N;
}

int main() {
  std::cout << fixed_multiply<int,2>(10) << '\n';
  std::cout << fixed_multiply<int,3>(10) << '\n';

fixed_multiply函数模板的第二个实参是int类型的。它看起来就像一个普通的函数形参,实际上也可以像普通函数形参一样使用。
但是有一个主要的区别:模板形参的值是在编译时确定的,以生成fixed_multiply函数的不同实例化,因此实参的值不会在运行时传递:main中对fixed_multiply函数的两次调用实质上调用了该函数的两个版本:一个总是乘以2,一个总是乘以3。出于同样的原因,第二个模板实参需要是一个常量表达式(它不能被传递为变量)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_40186813

你的能量无可限量。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值