C++ 重載函數與模板函數

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的函數。出於同樣的原因,第二個模板參數需要是一個常量表達式(不能傳遞一個變量給它)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章