程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++函數模板與類模板實例解析

C++函數模板與類模板實例解析

編輯:關於C++

C++函數模板與類模板實例解析。本站提示廣大學習愛好者:(C++函數模板與類模板實例解析)文章只能為提供參考,不一定能成為您想要的結果。以下是C++函數模板與類模板實例解析正文


本文針對C++函數模板與類模板停止了較為詳實的實例解析,有助於贊助讀者加深對C++函數模板與類模板的懂得。詳細內容以下:

泛型編程(Generic Programming)是一種編程范式,經由過程將類型參數化來完成在統一份代碼上操作多種數據類型,泛型是普通化並可反復應用的意思。泛型編程最後出生於C++中,目標是為了完成C++的STL(尺度模板庫)。

模板(template)是泛型編程的基本,一個模板就是一個創立類或函數的藍圖或公式。例如,當應用一個vector如許的泛型類型或許find如許的泛型函數時,我們供給足夠的信息,將藍圖轉換為特定的類或函數。

1、函數模板

一個通用的函數模板(function template)就是一個公式,可用來生成針對特定類型或特定值的函數版本。模板界說以症結字template開端,前面跟一個模板參數列表,列表中的多個模板參數(template parameter)以逗號分隔。模板參數表現在類或函數界說頂用到的類型或值。

1、類型參數

一個模板類型參數(type parameter)表現的是一品種型。我們可以將類型參數看做類型解釋符,就像內置類型或類類型解釋符一樣應用。類型參數前必需應用症結字class 或typename:

template <typename T> // typename和class一樣的 
T function(T* p) 
{ 
  T tmp = *p;  // 暫時變量類型為T 
  //... 
  return tmp;  // 前往值類型為T 
} 

症結字typename和class是一樣的感化,但明顯typename比class更加直不雅,它更清晰地指出隨後的名字是一個類型名。

編譯器用模板類型實參為我們實例化(instantiate)特定版本的函數,一個版本稱做模板的一個實例(instantiation)。當我們挪用一個函數模板時,編譯器平日用函數實參來為我們揣摸模板實參。固然假如函數沒有模板類型的參數,則我們須要特殊指出來:

int a = 10; 
cout << function(&a) << endl;   // 編譯器依據函數實參揣摸模板實參 
 
cout << function<int>(&a) << endl;  // <int>指出模板參數為int 

2、非類型參數

在模板中還可以界說非類型參數(nontype parameter),一個非類型參數表現一個值而非一個類型。我們經由過程一個特定的類型名而非症結字class或typename來指定非類型參數:

// 整形模板 
template<unsigned M, unsigned N> 
void add() 
{ 
  cout<< M+N << endl; 
} 
 
// 指針 
template<const char* C> 
void func1(const char* str) 
{ 
  cout << C << " " << str << endl; 
} 
 
// 援用 
template<char (&R)[9]> 
void func2(const char* str) 
{ 
  cout << R << " " << str << endl; 
} 
 
// 函數指針 
template<void (*f)(const char*)> 
void func3(const char* c) 
{ 
  f(c); 
} 
 
void print(const char* c) { cout << c << endl;} 
 
char arr[9] = "template";  // 全局變量,具有靜態生計期 
 
int main() 
{ 
  add<10, 20>(); 
  func1<arr>("pointer"); 
  func2<arr>("reference"); 
  func3<print>("template function pointer"); 
  return 0; 
} 

當實例化時,非類型參數被一個用戶供給的或編譯器揣摸出的值所替換。一個非類型參數可所以一個整型,或許是一個指向對象或函數的指針或援用:綁定到整形(非類型參數)的實參必需是一個常量表達式,綁定到指針或援用(非類型參數)的實參必需具有靜態的生計期(好比全局變量),不克不及把通俗部分變量 或靜態對象綁定到指針或援用的非類型形參。

2、類模板

響應的,類模板(class template)是用來生成類的藍圖。與函數模板的分歧的地方是,編譯器不克不及為類模板揣摸模板參數類型,所以我們必需顯式的供給模板實參。與函數模板一樣,類模板參數可所以類型參數,也能夠長短類型參數,這裡就不再贅述了。

template<typename T> 
class Array { 
public: 
  Array(T arr[], int s); 
  void print(); 
private: 
  T *ptr; 
  int size; 
}; 
 
// 類模板內部界說成員函數 
template<typename T> 
Array<T>::Array(T arr[], int s) 
{ 
  ptr = new T[s]; 
  size = s; 
  for(int i=0; i<size; ++i) 
    ptr[i]=arr[i]; 
} 
 
template<typename T> 
void Array<T>::print() 
{ 
  for(int i=0; i<size; ++i) 
    cout << " " << *(ptr+i); 
  cout << endl; 
} 
 
int main() 
{ 
  char a[5] = {'J','a','m','e','s'}; 
  Array<char> charArr(a, 5); 
  charArr.print(); 
 
  int b[5] = { 1, 2, 3, 4, 5}; 
  Array<int> intArr(b, 5); 
  intArr.print(); 
 
  return 0; 
}

類模板的成員函數

與其他類一樣,我們既可以在類模板外部,也能夠在類模板內部界說其成員函數。界說在類模板以外的成員函數必需以症結字template開端,後接類模板參數列表。

template <typename T> 
return_type class_name<T>::member_name(parm-list) { } 

默許情形下,關於一個實例化了的類模板,其成員函數只要在應用時才被實例化。假如一個成員函數沒有被應用,則它不會被實例化。

類模板和友元

當一個類包括一個友元聲明時,類與友元各自能否是模板是互相有關的。假如一個類模板包括一個非模板的友元,則友元被受權可以拜訪一切模板的實例。假如友元本身是模板,類可以受權給一切友元模板的實例,也能夠只受權給特定實例。

// 前置聲明,在將模板的一個特定實例聲明為友元時要用到 
template<typename T> class Pal; 
 
// 通俗類 
class C { 
  friend class Pal<C>; // 用類C實例化的Pal是C的一個友元 
  template<typename T> friend class Pal2; //Pal2一切實例都是C的友元;不必前置聲明 
}; 
 
// 模板類 
template<typename T> class C2 { 
  // C2的每一個實例將用雷同類型實例化的Pal聲明為友元,一對一關系 
  friend class Pal<T>; 
  // Pal2的一切實例都是C2的每一個實例的友元,不須要前置聲明 
  template<typename X> friend class Pal2;  
  // Pal3是通俗非模板類,它是C2一切實例的友元 
  friend class Pal3; 
}; 

類模板的static成員

類模板可以聲明static成員。類模板的每個實例都有其本身獨有的static成員對象,關於給定的類型X,一切class_name<X>類型的對象同享雷同的一份static成員實例。

template<typename T> 
class Foo { 
public: 
  void print(); 
  //...其他操作 
private: 
  static int i; 
}; 
 
template<typename T> 
void Foo<T>::print() 
{ 
  cout << ++i << endl; 
} 
 
template<typename T> 
int Foo<T>::i = 10; // 初始化為10 
 
int main() 
{ 
  Foo<int> f1; 
  Foo<int> f2; 
  Foo<float> f3; 
  f1.print();  // 輸入11 
  f2.print();  // 輸入12 
  f3.print();  // 輸入11 
  return 0; 
}

我們可以經由過程類類型對象來拜訪一個類模板的static對象,也能夠應用感化域運算符(::)直接拜訪靜態成員。相似模板類的其他成員函數,一個static成員函數也只要在應用時才會實例化。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved