程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 我也來談一談c++模板(一),也來談c模板

我也來談一談c++模板(一),也來談c模板

編輯:C++入門知識

我也來談一談c++模板(一),也來談c模板


    c++中程序員使用模板能夠寫出與類型無關的代碼,提高源代碼重用,使用合適,大大提高了開發效率。此前,可以使用宏實現模板的功能,但是模板更加安全、清晰。在編寫模板相關的代碼是我們用到兩個關鍵詞:template和class(或者typename),class和typename基本沒有區別。

1、函數模板

     函數模板本質上就是實現針對不同類型的同一種算法的代碼,其基本用法可以是形如:

 template <class TYPE ,class TYPE,......>

 ReturnValue function(Argments)

 {

 // code

 }

     這裡template <class TYPE ,class TYPE,......> 聲明了此段代碼是一段模板。”<>“中提供的是模板的類型參數,當使用這段代碼時,編譯器會根據使用的實際類型產生一份實例。在接下來的整個函數模板中就可以使用類型參數了,函數的returnvalue,arguments,local variable都可以使用類型參數。下面是一段簡單的函數模板使用實例:

 1 template <class T> T foo(T& lhs,T& rhs)
 2 {
 3     T tmp = lhs;
 4     lhs = rhs;
 5     rhs = tmp;
 6     return lhs>rhs?lhs:rhs;
 7 }
 8 
 9 int main()
10 {
11     int a(5),b(10);
12     cout << foo(a,b) << endl;
13     cout << "a=" << a << endl;
14     cout << "b=" << b << endl; 
15 
16     string c("hello"),d("world");
17     cout << foo(c,d) << endl;
18     cout << "c=" << c << endl;
19     cout << "d=" << d << endl;
20 }

    1-5行就是函數模板的基本使用方式,foo()函數的功能是交換兩個參數,然後返回較大的值,但是foo()函數並不關心參數的類型 。當我們在main()中使用foo模板是,分別使用int和string類型都能得到期望的結果,而foo的代碼只寫了一份,沒有針對int和string。

這是輸出結果:

10
a=10
b=5
world
c=world
d=hello

2、類中的函數模板

    類中含有成員函數模板的情況和上一種情況類似,只是限定了一下作用域。說實話,這一種情況應該比上一種情況更加常見,因為c++是一門面向對象的語言,我們定義的函數,通常需要定義在類中,盡量減少全局函數的使用。當然有點扯遠了,寫個小例子,說明用法:

class X
{
public:
   template <class T> 
  void mf(T* t) {} }; int main() { int i; X* x = new X(); x->mf(&i); }

    基本和第一種情況一樣,不再贅述了。

3、簡單的類模板

    定義類模板的語法通項可以是這樣的公式:

template<class TYPE,class TYPE...>

class CLASSNAME

{

  //members.

};

template<class TYPE,class TYPE...>

ReturnValue CLASSNAME<TYPE,TYPE...>::function (Arguments)

{

  //code.

}

    類模板的使用大體和函數模板類似,只是要注意一點,當聲明和定義相分離時,定義成員函數的時候,光限定模板名是不夠的,要加上類型,只有這樣限定才會是一個類名而非模板。舉個例子:

template <class T>
class Bar {
    void foo();
};

template<class t>
void Bar<T>::foo()
{
    //
}

void Bar<T>::foo()是重要的,這是使用模板最常見的錯誤之一了。Bar只是模板而Bar<T>才是類名。

4、類模板中的函數模板

    類中的成員函數也可以是一個模板,這樣就形成了一種層次關系。需要注意的是,在定義成員函數函數模板的時候需要在上例的基礎上,考慮模板間的層次關系。例如這樣一段代碼:

 1 template<typename T>
 2 class X
 3 {
 4 public:
 5    template<typename U>
 6    void mf(const U &u);
 7 };
 8 
 9 template<typename T> 
10 template <typename U>
11 void X<T>::mf(const U &u)
12 {
13 }
14 
15 int main()
16 {
17 }

  9-10行中限定了兩個類型參數T、U的層次,其中U是成員函數函數模板的類型參數,如果11行這樣寫:

void X<U>::mf(const T &u)

   就會報錯。

還有一點需要注意的是:

Member template functions cannot be virtual functions and cannot override virtual functions from a base class when they are declared with the same name as a base class virtual function.

當使用與基類虛函數相同的名稱進行聲明時,成員模板函數不能是虛函數並且不能從基類重寫虛函數。

   關於之間的區別還是寫兩段代碼具體的感受一下比較好。

5、在普通類中嵌套類模板

    嵌套類模板被聲明為外部類范圍內的類模板,可以在封閉類的內部或外部定義它們。通俗點說就是嵌套類模板的作用范圍是它所在類的裡邊,嵌套類的定義可以在外邊定義。,如下是一段msdn上面的嵌套類的簡單例子: 

 1 #include <iostream>
 2 using namespace std;
 3 
 4 class X
 5 {
 6 
 7    template <class T>
 8    struct Y
 9    {
10       T m_t;
11       Y(T t): m_t(t) { }   
12    };
13 
14    Y<int> yInt;
15    Y<char> yChar;
16 
17 public:
18    X(int i, char c) : yInt(i), yChar(c) { }
19    void print()
20    {
21       cout << yInt.m_t << " " << yChar.m_t << endl;
22    }
23 };
24 
25 int main()
26 {
27    X x(1, 'a');
28    x.print();
29 }

   struct Y就是嵌套在class X中的一個類模板,在X類中模板Y實例化出了2個類型實例,分別是Y<int> 、Y<char>。此後所有的操作可以把Y<int>、Y<char>看做一個普通的類類型。

6、在類模板中嵌套類模板

     與上一種情況類似,只是這次外層類是一個類模板,而非具體的類類型。這種情況下最值得注意的就是:

When nested class templates are defined outside of their enclosing class, they must be prefaced by the template parameters for both the class template (if they are members of a class template) and template parameters for the member template.

當嵌套類模板在其封閉類的外部定義時,它們必須以類模板(如果它們是類模板的成員)的模板參數和成員模板的模板參數開頭。------MSDN手冊

    翻譯的也是比較拗口,但是讀幾遍的話也很好理解:當定義嵌套類時我們需要考慮的是,也就是第3中情況提到的需要注意的情況,”::“域作用符是作用於類上的,而非模板上的。所以如果在外部定義嵌套類時,首先我們不僅要在外層類模板後帶上模板參數,使其形式上(還沒有實例化)成為一個類,嵌套類也需要加上模板參數,使其形式上成為一個類。

 1 #include <iostream>
 2 using namespace std;
 3 
 4 template <class T>
 5 class X
 6 {
 7    template <class U> class Y
 8    {
 9       U* u;
10    public:
11       Y();
12       U& Value();
13       void print();
14       ~Y();
15    };
16 
17    Y<int> y;
18 public:
19    X(T t) { y.Value() = t; }
20    void print() { y.print(); }
21 };
22 
23 template <class T> 
24 template <class U>
25 X<T>::Y<U>::Y()
26 {
27    cout << "X<T>::Y<U>::Y()" << endl;
28    u = new U();
29 }
30 
31 template <class T> 
32 template <class U>
33 U& X<T>::Y<U>::Value()
34 {
35    return *u;
36 }
37 
38 template <class T> 
39 template <class U>
40 void X<T>::Y<U>::print()
41 {
42    cout << this->Value() << endl;
43 }
44 
45 template <class T> 
46 template <class U>
47 X<T>::Y<U>::~Y()
48 {
49    cout << "X<T>::Y<U>::~Y()" << endl;
50    delete u;
51 }
52 
53 int main()
54 {
55    X<int>* xi = new X<int>(10);
56    X<char>* xc = new X<char>('c');
57    xi->print();
58    xc->print();
59    delete xi;
60    delete xc;
61 }

    最後還值得注意的是,正如第四種情況那樣,嵌套類與外層類的模板參數也有層次關系。通常寫成兩行:

template <class T>
template <class U>

    T被當成外層類的模板參數,U被當成嵌套類的模板參數。我看有的書上便於區分會寫成縮進的形式:

template <class T>
  template <class U>

   關於模板的知識多,暫時沒精力寫了,明天再接著寫下去。有哪些地方不到位的,還請各位看官指正,謝謝。本人QQ:5435620.EMAIL:[email protected]

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