由于想要對STL的具體實(shí)現(xiàn)有一個清楚的認(rèn)識,因此在此先溫習(xí)一下關(guān)于templates的相關(guān)知識。
模版的使用,將不同類型的具體實(shí)現(xiàn)交給了編譯器去完成,從而實(shí)現(xiàn)了代碼量的縮減,以達(dá)到清晰鮮明的目的。
如有個函數(shù)
1: template <typename Type> // this is the template parameter declaration
2: Type max(Type tX, Type tY)
3: {
4: return (tX > tY) ? tX : tY;
5: }
當(dāng)你在編譯程序時,編譯器遇到相應(yīng)的調(diào)用
1: int nValue = max(3, 7); // calls max(int, int)
那么編譯器將會對模版函數(shù)進(jìn)行一次復(fù)制,并將類型改成相應(yīng)的int類型,實(shí)現(xiàn)template instance.
1: int max(int tX, int tY)
2: {
3: return (tX > tY) ? tX : tY;
4: }
在模版的使用中,除了具體類型可以外,還可以是表達(dá)式參數(shù).
表達(dá)式參數(shù)可以是下面這些值:
1. 整型或是枚舉
2. 對象的指針或是引用
3. 函數(shù)的指針或是引用
4. 類成員函數(shù)的指針或是引用
如:
1: template <typename T, int nSize> // nSize is the expression parameter
2: class Buffer
3: {
4: private:
5: // The expression parameter controls the size of the array
6: T m_atBuffer[nSize];
7:
8: public:
9: T* GetBuffer() { return m_atBuffer; }
10:
11: T& operator[](int nIndex)
12: {
13: return m_atBuffer[nIndex];
14: }
15: };
16:
17: int main()
18: {
19: // declare an integer buffer with room for 12 chars
20: Buffer<int, 12> cIntBuffer;
21:
22: // Fill it up in order, then print it backwards
23: for (int nCount=0; nCount < 12; nCount++)
24: cIntBuffer[nCount] = nCount;
25:
26: for (int nCount=11; nCount >= 0; nCount--)
27: std::cout << cIntBuffer[nCount] << " ";
28: std::cout << std::endl;
29:
30: // declare a char buffer with room for 31 chars
31: Buffer<char, 31> cCharBuffer;
32:
33: // strcpy a string into the buffer and print it
34: strcpy(cCharBuffer.GetBuffer(), "Hello there!");
35: std::cout << cCharBuffer.GetBuffer() << std::endl;
36:
37: return 0;
38: }
模版中類型的特例化
看一下下面這個類:
1: using namespace std;
2:
3: template <typename T>
4: class Storage
5: {
6: private:
7: T m_tValue;
8: public:
9: Storage(T tValue)
10: {
11: m_tValue = tValue;
12: }
13:
14: ~Storage()
15: {
16: }
17:
18: void Print()
19: {
20: std::cout << m_tValue << std::endl;;
21: }
22: };
如果采用下面的例子進(jìn)行調(diào)用:
1: int main()
2: {
3: using namespace std;
4:
5: // Dynamically allocate a temporary string
6: char *strString = new char[40];
7:
8: // Ask user for their name
9: cout << "Enter your name: ";
10: cin >> strString;
11:
12: // Store the name
13: Storage<char*> strValue(strString);
14:
15: // Delete the temporary string
16: delete strString;
17:
18: // Print out our value
19: strValue.Print(); // This will print garbage
20: }
來看一下此時類的構(gòu)造:
1: Storage<char*>::Storage(char* tValue)
2: {
3: m_tValue = tValue;
4: }
可以明顯的發(fā)現(xiàn)m_tValue和strString指向同一塊內(nèi)存空間。
采用delete將strString刪除后,使得m_tValue指向的內(nèi)容也變成沒有定義的了。而上面這個類在對于int類型的時候能夠很好的實(shí)現(xiàn)。因此對于char*類型需要特殊對待。如下:
1: Storage<char*>::Storage(char* tValue)
2: {
3: // Allocate memory to hold the tValue string
4: m_tValue = new char[strlen(tValue)+1];
5: // Copy the actual tValue string into the m_tValue memory we just allocated
6: strcpy(m_tValue, tValue);
7: }
1: Storage<char*>::~Storage()
2: {
3: delete[] m_tValue;
4: }
整個類的特例化:
1: template <typename T>
2: class Storage8
3: {
4: private:
5: T m_tType[8];
6:
7: public:
8: void Set(int nIndex, const T &tType)
9: {
10: m_tType[nIndex] = tType;
11: }
12:
13: const T& Get(int nIndex)
14: {
15: return m_tType[nIndex];
16: }
17: };
上面這個類對于int的時候能夠很好的實(shí)現(xiàn),但是遇到bool時,由于bool的信息只用一個位就能夠表示,而內(nèi)存的最小存儲單元是一個字節(jié),因此采用上述的類存儲bool的內(nèi)存中有7/8是浪費(fèi)的,因此采用另一種方式進(jìn)行實(shí)現(xiàn),構(gòu)建一個新的類需要使用不用的變量名,使得使用的時候有一定的麻煩,因此采用了對整個類的特例化。
1: template <> // the following is a template class with no templated parameters
2: class Storage8<bool> // we're specializing Storage8 for bool
3: {
4: // What follows is just standard class implementation details
5: private:
6: unsigned char m_tType;
7:
8: public:
9: void Set(int nIndex, bool tType)
10: {
11: // Figure out which bit we're setting/unsetting
12: // This will put a 1 in the bit we're interested in turning on/off
13: unsigned char nMask = 1 << nIndex;
14:
15: if (tType) // If we're setting a bit
16: m_tType |= nMask; // Use bitwise-or to turn that bit on
17: else // if we're turning a bit off
18: m_tType &= ~nMask; // bitwise-and the inverse mask to turn that bit off
19: }
20:
21: bool Get(int nIndex)
22: {
23: // Figure out which bit we're getting
24: unsigned char nMask = 1 << nIndex;
25: // bitwise-and to get the value of the bit we're interested in
26: // Then implicit cast to boolean
27: return m_tType & nMask;
28: }
29: };