Cpp/C++

C++ 重载函数与模板函数

2018-10-18  本文已影响10人  Jimmy_L_Wang

Overloaded functions 重载函数

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

在这个例子中,两个函数都有完全不同的行为,int版本乘以它的参数,而double版本参数相除。这通常不是一个好主意。通常期望具有相同名称的两个函数具有至少相似的行为,但是该示例表明它们完全可能不具有相同的行为。两个重载函数(即两个具有相同名称的函数)具有完全不同的定义; 出于所有目的,它们是不同的功能,只是恰好具有相同的名称。

请注意,函数不能仅通过其返回类型重载。其参数中至少有一个必须具有不同的类型。

Overloaded operator 运算符重载

除了可以重载函数,C++还可以重定义或重载大部分 C++ 内置的运算符。这样,您就能使用自定义类型的运算符了。

重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。

Box operator+(const Box&);

声明加法运算符用于把两个 Box 对象相加,返回最终的 Box 对象。大多数的重载运算符可被定义为普通的非成员函数或者被定义为类成员函数。如果我们定义上面的函数为类的非成员函数,那么我们需要为每次操作传递两个参数,如下所示:

Box operator+(const Box&, const Box&);

例子:

 Box operator+(const Box& b)
    {
        Box box;
        box.length = this->length + b.length;
        box.breadth = this->breadth + b.breadth;
        box.height = this->height + b.height;
        return box;
    }

Function templates 函数模板

重载的函数可能具有相同的定义。

C++能够使用泛型类型定义函数,称为函数模板。定义函数模板遵循与常规函数相同的语法,除了它之前是template关键字和用括号<>括起来的一系列模板参数:

template <template-parameters> function-declaration 

模板参数是由逗号分隔的一系列参数。这些参数可以通过指定是通用模板的类型的任一classtypename关键字后跟标识符。然后,可以在函数声明中使用此标识符,就像它是常规类型一样。例如,泛型sum函数可以定义为:

template <class SomeType>
SomeType sum (SomeType a, SomeType b)
{
  return a+b;
}

在模板参数列表中 使用关键字class或关键字typename来指定泛型类型是没有区别的(它们在模板声明中是100%同义词)

在上面的代码中,声明SomeType(包含在尖括号中的模板参数中的泛型类型)允许SomeType在函数定义中的任何位置使用,就像任何其他类型一样; 它可以用作参数的类型,返回类型,或声明此类型的新变量。在所有情况下,它表示将在模板实例化时确定的泛型类型。

实例化模板的过程是应用模板来创建函数并使用特定类型来创建模板参数。调用函数模板时,使用与调用常规函数相同的语法,但指定< >中的模板参数:

name <template-arguments> (function-arguments)

例如:

x = sum<int>(10,20);

来看一个完整的例子:

// 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用作参数的特定情况下sum,编译器甚至能够自动推导出数据类型,而无需在尖括号内明确指定它。例如上面:

  k=sum<int>(i,j);
  h=sum<double>(f,g);

可以简单地写:

k = sum (i,j);
h = sum (f,g);

模板是一种功能强大且功能多样的函数。它们可以有多个模板参数,该函数仍然可以使用常规的非模板化类型。如:

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

Non-type template arguments 非类型模板参数

模板参数不仅可以包含由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,因而该参数的值在运行时不会传递:两个fixed_multiply的调用在main内本质上是调用了的两个版本函数:总是乘以2的函数,总是乘以3的函数。出于同样的原因,第二个模板参数需要是一个常量表达式(不能传递一个变量给它)。

上一篇下一篇

猜你喜欢

热点阅读