模板和標準模板庫(STL) 一、模板的起源 變數四要素:類型、名稱、值、地址 數據類型:存儲形式、編碼格式、運算規則、訪問方式 int a = 0; // 補碼 float b = 0; // 階碼 char c = 'A'; // ASCII char_t d = 'A'; // UCS 4 in ...
模板和標準模板庫(STL) 一、模板的起源 變數四要素:類型、名稱、值、地址 數據類型:存儲形式、編碼格式、運算規則、訪問方式 int a = 0; // 補碼 float b = 0; // 階碼 char c = 'A'; // ASCII char_t d = 'A'; // UCS-4 int i = 0; i++; cout << i << endl; // 1 int* j = (int*)0; j++; cout << (int)j << endl; // 4 class Student ; Student stu (...); stu.m_name = ...; Student* pstu = &stu; pstu->learn (...); 靜態類型:由編譯器在編譯源代碼的過程中,處理有關數據類型的檢查、指令等問題,並將處理結果直接反應在所生成的二進位機器指令中。
Python
i = 10 i = 1.2 i = 'Hello, World !' 靜態類型的優點:運行性能好,安全。 靜態類型的缺點:缺乏靈活性,不具備泛型能力。 代碼:typed.cpp 藉助於帶參巨集(巨集函數)可以在某種程度上規避源自靜態類型系統的限制,但同時也因為類型檢查和轉換的缺少而引入潛在的風險。 代碼:untyped.cpp 通過巨集描述類型無關演算法的框架,藉助預處理器自動生成針對不同數據類型的具體版本,達到類型安全和類型無關的效果。 代碼:macro.cpp 顯示擴展巨集,預處理器缺乏類型分析能力。 巨集的調試非常困難。 二、函數模板 1.定義 template<typename 類型形參1, typename 類型形參2, ...> 返回類型 函數模板名 (調用形參表) { 函數體 } 在函數模板的返回類型、調用形參表乃至函數體中都可以引用該函數模板的類型形參。 template<typename A, typename b, typename _C> A fun (b arg) { _C var; ... } 2.使用 函數模板名<類型實參1, 類型實參2, ...> (調用實參表); 當編譯器"看到"以上調用語句,就會用尖括弧中的類型實參表與所調用函數模板尖括弧中的類型形參表,按照從前到後,依次結合,把模板化的函數編成一個具體函數,編譯成二進位機器指令,滿足調用的需要。這個過程就叫做函數模板的實例化。 代碼:ftmpl.cpp 3.類型參數 1)類型形參:必須用typename/class關鍵字修飾,而且必須其名稱必須是合法的標識符。 2)類型實參:既可以是基本類型,也可以是標準庫、第三方庫、或者開發者自己編寫的類類型,唯一的條件就是必須滿足函數模板內部實現的需要。 代碼:targ.cpp 4.延遲編譯 在構建過程中一個非模板函數,只被編譯一次,而且是在其定義被編譯器發現的時候。 在構建過程中一個模板函數,至少要經歷兩次編譯過程,第一次是在其定義被編譯器發現時,這時編譯器會對該函數模板做與類型無關的語法檢查,而後會在其內部生成關於該函數模板的內部表示;第二次是在其調用語句被編譯器發現時,這時編譯器會將調用語句所提供的類型實參與內部表示中的類型形參結合,做與類型相關的語法檢查,而後將該函數模板以具體函數的形式編譯成二進位機器指令。 代碼:typename.cpp 5.隱式推斷 如果函數模板調用參數(圓括弧里的參數)的類型相關於該模板的模板參數(尖括弧里的參數),即使不顯式指定模板參數的類型,編譯器也可以根據函數調用虛實參數類型匹配的原則,隱式推斷出模板參數的實際類型,這就叫函數模板類型參數的隱式推斷。但是,如果隱式推斷的類型與代碼編寫者所期望的類型不一致,可能產生未定義的後果。 代碼:deduction.cpp 6.重載 函數模板和普通函數一樣,也可以構成重載關係,二者區別在於,對重載版本的解析,如果是函數模板,在類型匹配程度相當的情況下,編譯器並不會立即以歧義為由報錯,相反會進一步檢查不同重載版本的類型針對性,並優先選擇針對性較強的版本。 代碼:overload.cpp 三、類模板 如果一個類的成員變數、成員函數、成員類型乃至基類中包含參數化的類型,那麼這個類就是一個類模板。 1.定義 template<typename 類型形參1, typename 類型形參2, ...> class 類模板名 [: 繼承方式 基類, ...] { 成員變數 成員函數 成員類型 }; 其中成員變數、成員函數、成員類型、基類都可以引用該類模板的類型參數。 class X ; class A : public X ; class B : public X ; class C : public X ; template
3.靜態成員變數 語法:需要用static關鍵字聲明,在類外定義初始化。 邏輯:類的一部分而非對象的一部分,被類的所有對象共用。 物理:存在進程的靜態存儲區(DAT/BSS)。
類型:主詞,副詞,飾詞 int const* p ...; static/auto/register
類模板中的靜態成員變數,是該類模板的每個實例化類的一部分,在該實例化類被實例化為對象時,被這些對象共用。 / X -> x1, x2, x3 A - Y -> y1, y2, y3 s \ Z -> z1, z2, z3 代碼:static.cpp 4.容器 通過數組存放多個類型相同的數據 int a = 10, b = 20; a = b; cout << a << endl; // 20 void foo (int a) { ++a; } foo (a); cout << a << endl; // 20 int bar (void) { int c = 30; return c; } c = bar (); cout << c << endl; // 30
int a[] = {10}, b[] = {20}; a = b; // ERROR void foo (int a[1]) { ++a[0]; } foo (a); cout << a[0] << endl; // 11
int* bar (void) { int c[] = 30; return c; } int* c = bar (); cout << c << endl; // 30? 數組容器 遞歸實例化:用一個類模板的實例化類實例化該類模板自身,以獲得在空間上具有遞歸特征的數據結構。 代碼:array.cpp 嵌套實例化:用一種數據結構的模板實例實例化另一種數據結構的模板實例,以獲得空間上的複合結構。 template p = &i; // p -> i int* q = p; // q __/ smart_ptr