1. 程式人生 > 程式設計 >C++ 泛型程式設計詳解

C++ 泛型程式設計詳解

泛型程式設計與面向物件程式設計的目標相同,即使重用程式碼和抽象通用概念的技術更加簡單。但是面向物件程式設計強調程式設計的資料方面,泛型程式設計強調的是獨立於特定資料型別。

這一篇介紹一下 C++ 程式設計中與面向物件並列的另一大分支——泛型程式設計,這一篇主要介紹函式模板、類模板和成員模板三大部分

如有侵權,請聯絡刪除,如有錯誤,歡迎大家指正,謝謝

泛型程式設計

模板是泛型程式設計的一種重要思想,STL(Standard Template Library,標準模板庫)是採用模板實現的一個例項
函式模板

對比函式過載(同一作用域內函式名相同,引數列表不同的函式),函式模板只需要一個函式就實現了函式過載的部分功能(引數個數相同型別不同,函式過載需要定義多個同名引數列表不同的函式)

template<typename T,typename Y> // 這也可以寫 template<class T,class Y> 此處的 class 和 typename 作用相同
void tfunc(T& t,Y& y) {
 cout << t << " " << y << endl;
}
int n = 2;
double d = 2.1;
tfunc(n,d);

// 執行結果:2 2.1

函式模板具體化,函式模板具體化就是將某一(某幾)個要處理的型別單獨處理,需要單獨寫一個實現,形式是 template<> void fun(type& t);,函式模板的具體化和普通函式可以同時存在,呼叫順序是 普通函式 > 函式模板具體化 > 模板函式

// ====== 測試一:函式模板針對特殊資料型別具體化 ======
struct Node {
 int val;
 Node* next;
};
// 函式模板
template<typename T> 
void tfunc(const T& t) {
 cout << "template: " << t << endl;
}
// 函式模板具體化(用於處理Node型別資料)
template<> 
void tfunc<Node>(const Node& node) {
 cout << "template<Node>: " << node.val << endl;
}
// 函式模板具體化(用於處理int型別資料)
template<> 
void tfunc<int>(const int& n) {
 cout << "template<int>: " << n << endl;
}
// 普通函式
void tfunc(const int& n) {
 cout << "tfunc(): " << n << endl;
}
double d = 2.1;
tfunc(d); // 函式模板未具體化double型別函式,呼叫模板
Node node{ 2,nullptr };
tfunc(node); // 函式模板具體化Node型別函式,呼叫函式模板的具體化
int n = 2;
tfunc(n); // 函式模板具體化int型別函式,也存在普通函式,呼叫普通函式
// ====== 測試二:函式模板部分具體化 ======
template<typename T1,typename T2>
void tfunc(T1 t1,T2 t2) {
 cout << typeid(T1).name() << " and " << typeid(T2).name() <<": " << t1 << " " << t2 << endl;
}
template<typename T1>
void tfunc(T1 t1,int i) {
 cout << typeid(T1).name() << " and " << "int: " << t1 << " " << i << endl;
}
template<typename T2>
void tfunc(long l,T2 t2) {
 cout << "long and " << typeid(T2).name() << ": " << l << " " << t2 << endl;
}
template<>
void tfunc(short l,int i) {
 cout << "long and int: " << l << " " << i << endl;
}
// 分別呼叫以上四個模板函式
tfunc(char('c'),char('c'));
tfunc(char('c'),int(10));
tfunc(long(10),char('c'));
tfunc(short(10),int(10));

函式模板例項化,讓編譯器生成指定型別的函式定義,不用寫函式的實現,形式是 template void fun(type& t);

// 函式模板
template<typename T> 
void tfunc(const T& t) {
 cout << "template: " << t << endl;
}

// 函式模板例項化,不用寫函式的實現,編譯器會生成該型別的模板具體化函式
template void tfunc<char>(const char& c);

類模板

類模板可以指定預設模板引數(函式模板不可以),跟函式引數的預設值一樣,必須從右向左連續賦值預設型別,如果例項化物件時又傳遞了型別,預設型別會被覆蓋掉,跟函式引數是一樣的
建立物件時需要傳遞模板引數列表,模板引數列表加在類名後面 ClassName< typename T > classN; 如果類的模板引數列

表有預設值,可以不傳模板引數,但一定要加 <> 如 ClassName< > classN; 建立堆區物件的時候,所有的類名稱後面都要加模板引數列表,如 ClassName< typename T >* classN = new ClassName< typename T>; 除了類內,其他地方出現 ClassName 的地方一般都要加模板引數列表

template<typename T = int,typename Y = char> // 此處指定了模板預設引數,部分指定必須從右到左指定
class Test {
public:
 Test(T t,Y y) : t(t),y(y) {
 }
 void tfunc();
private:
 T t;
 Y y;
};
template<typename T,typename Y> // 類模板的函式在類外實現,需要加上模板引數列表,但不需要加指定的預設模板引數
void Test<T,Y>::tfunc() { // 類外使用Test需要加模板引數
 cout << t << " " << y << endl;
}
int n = 2;
double d = 2.1;
Test<int,double> test(n,d); // 此處如果使用預設模板引數可定義為 Test<> test(int(2),char('a'));
test.tfunc();
// 執行結果:2 2.1

類模板的繼承,類模板被繼承後引數的傳遞方式主要有兩種,一種是直接在子類繼承父類的時候,為父類指定固定的型別,二是通過子類模板引數列表傳遞

// ====== 測試一 ======
template<typename T,typename Y>
class A {
public:
 A(T t,Y y) {
 }
};
class Test : public A<int,double> { // 父類是類模板,子類是普通類
public:
 Test() : A<int,double>(2,2.1) {
 }
};
Test();
// ====== 測試二 ======
template<typename T,typename Y>
class A {
public:
 A(T t) {
 }
};
template<typename X,typename Z,typename P>
class Test : public A<X,P> {
public:
 Test(X x,Z z,P p) : A<X,P>(x) {
 }
};
Test<int,double,char>(int(2),double(2.1),char('a'));

類模板的多型,在建立物件時,分為子類沒有模板(CFather<short,char>*cf = new CSon;)和子類有模板(CFather<short,char> *cf = new CSon<short,int,char>)兩種,子類和父類的模板引數列表可以不一樣,但一定要對應好

// ====== 測試一 ======
template<typename T,typename Y> 
class A {
public:
 virtual void tfunc(T t,Y y) = 0;
};
class Test : public A<int,double> { 
public:
 virtual void tfunc(int n,double d) {
 cout << n << " " << d << endl;
 }
};
// 父類是類模板,子類是普通類,在多型情況下父類需要指定模板引數,子類就不用了
A<int,double>* a = new Test;
a->tfunc(2,2.1);
// 執行結果:2 2.1
// ====== 測試二 ======
template<typename T,Y y) = 0;
};
template<typename X,P> {
public:
 virtual void tfunc(X x,P p) {
 cout << x << " " << p << endl;
 }
};

// 父類是類模板,子類是類模板,在多型情況下父類和子類都需要指定模板引數
A<int,double>* a = new Test<int,char,double>;
a->tfunc(2,2.1);
// 執行結果:2 2.1

類模板具體化,類模板的具體化分為部分具體化和全部具體化兩種

template<typename T1,typename T2>
class Test {
public:
 Test() {
 cout << "T1 and T2" << endl;
 }
};
// 部分具體化
template<typename T1>
class Test<T1,int> {
public:
 Test() {
 cout << "T1 and int" << endl;
 }
};
// 部分具體化
template<typename T2>
class Test<long,T2> {
public:
 Test() {
 cout << "long and T2" << endl;
 }
};
// 全部具體化
template<>
class Test<long,int> {
public:
 Test() {
 cout << "long and int" << endl;
 }
};
// 分別建立上面四個類
Test<char,char>();
Test<char,int>();
Test<long,char>();
Test<long,int>();

成員模板

成員模板簡單說就是模板中的模板

class Base1 { };
class Base2 { };
class Test1 : public Base1 { };
class Test2 : public Base2 { };
template<typename T1,typename T2> 
class Pair {
public:
 T1 t1;
 T2 t2;
 Pair(T1 t1,T2 t2) : t1(t1),t2(t2) {
 }
 // 類模板中的成員模板
 template<typename U1,typename U2>
 Pair(const Pair<U1,U2>& pair) : t1(pair.t1),t2(pair.t2){
 }
};
Pair<Base1*,Base2*>(Pair<Test1*,Test2*>(new Test1,new Test2));

如果未特殊說明,以上測試均是在win10 vs2017 64bit編譯器下進行的

總結

以上所述是小編給大家介紹的C++ 泛型程式設計,希望對大家有所幫助!