DuiLib 源碼分析之CDuiString


duilib是一個比較常見的界面庫,閑來無事看看別人寫的代碼,跟自己寫的一比,

才看到了差距呀,感覺自己寫的亂七八糟,keep moving

CduiString是duilib提供的一個字符串類,功能是夠用的,做duilib項目可以直接拿來用

首先看看頭文件定義:

 1 class UILIB_API CDuiString
 2     {
 3     public:
 4         enum { MAX_LOCAL_STRING_LEN = 63 };
 5 
 6         CDuiString();
 7         CDuiString(const TCHAR ch);
 8         CDuiString(const CDuiString& src);
 9         CDuiString(LPCTSTR lpsz, int nLen = -1);
10         ~CDuiString();
11 
12         void Empty();
13         int GetLength() const;
14         bool IsEmpty() const;
15         TCHAR GetAt(int nIndex) const;
16         void Append(LPCTSTR pstr);
17         void Assign(LPCTSTR pstr, int nLength = -1);
18         LPCTSTR GetData() const;
19 
20         void SetAt(int nIndex, TCHAR ch);
21         operator LPCTSTR() const;
22 
23         TCHAR operator[] (int nIndex) const;
24         const CDuiString& operator=(const CDuiString& src);
25         const CDuiString& operator=(const TCHAR ch);
26         const CDuiString& operator=(LPCTSTR pstr);
27 #ifdef _UNICODE
28         const CDuiString& CDuiString::operator=(LPCSTR lpStr);
29         const CDuiString& CDuiString::operator+=(LPCSTR lpStr);
30 #else
31         const CDuiString& CDuiString::operator=(LPCWSTR lpwStr);
32         const CDuiString& CDuiString::operator+=(LPCWSTR lpwStr);
33 #endif
34         CDuiString operator+(const CDuiString& src) const;
35         CDuiString operator+(LPCTSTR pstr) const;
36         const CDuiString& operator+=(const CDuiString& src);
37         const CDuiString& operator+=(LPCTSTR pstr);
38         const CDuiString& operator+=(const TCHAR ch);
39 
40         bool operator == (LPCTSTR str) const;
41         bool operator != (LPCTSTR str) const;
42         bool operator <= (LPCTSTR str) const;
43         bool operator <  (LPCTSTR str) const;
44         bool operator >= (LPCTSTR str) const;
45         bool operator >  (LPCTSTR str) const;
46 
47         int Compare(LPCTSTR pstr) const;
48         int CompareNoCase(LPCTSTR pstr) const;
49 
50         void MakeUpper();
51         void MakeLower();
52 
53         CDuiString Left(int nLength) const;
54         CDuiString Mid(int iPos, int nLength = -1) const;
55         CDuiString Right(int nLength) const;
56 
57         int Find(TCHAR ch, int iPos = 0) const;
58         int Find(LPCTSTR pstr, int iPos = 0) const;
59         int ReverseFind(TCHAR ch) const;
60         int Replace(LPCTSTR pstrFrom, LPCTSTR pstrTo);
61 
62         int __cdecl Format(LPCTSTR pstrFormat, ...);
63         int __cdecl SmallFormat(LPCTSTR pstrFormat, ...);
64 
65     protected:
66         LPTSTR m_pstr;//指向緩沖區的指針,可能指向m_szBuffer,也可能指向別的緩沖區
67         TCHAR m_szBuffer[MAX_LOCAL_STRING_LEN + 1];//儲存字符串的字符數組
68     };

看了定義之后其中的api大部分都會使用了吧

下面抓幾個重要的函數來分析一下吧.

 1 void CDuiString::Append(LPCTSTR pstr)
 2     {
 3         int nNewLength = GetLength() + (int) _tcslen(pstr);
 4         if( nNewLength >= MAX_LOCAL_STRING_LEN ) {
 5             if( m_pstr == m_szBuffer ) {
 6                 m_pstr = static_cast<LPTSTR>(malloc((nNewLength + 1) * sizeof(TCHAR)));
 7                 _tcscpy(m_pstr, m_szBuffer);
 8                 _tcscat(m_pstr, pstr);
 9             }
10             else {
11                 m_pstr = static_cast<LPTSTR>(realloc(m_pstr, (nNewLength + 1) * sizeof(TCHAR)));
12                 _tcscat(m_pstr, pstr);
13             }
14         }
15         else {
16             if( m_pstr != m_szBuffer ) {//防止m_pstr指向別的地方
17                 free(m_pstr);
18                 m_pstr = m_szBuffer;
19             }
20             _tcscat(m_szBuffer, pstr);
21         }
22     }

Append函數用於在末尾添加字符串,首先判斷添加后的的字符串長度是否比默認數組中能儲存的長。1.超過了:先判斷當前指針是否指向m_szBuffer,是的話則新申請一段內存,將原有的內容復制過去,再加上新增的即可,否的話先釋放m_pstr中的內存再復制內容,新增。(注意這里realloc函數會在申請內存給m_pstr后將原有內容復制過去,並且釋放原來m_pstr的內存)2.沒有超過則直接添加即可

 1 void CDuiString::Assign(LPCTSTR pstr, int cchMax)
 2     {
 3         if( pstr == NULL ) pstr = _T("");
 4         cchMax = (cchMax < 0 ? (int) _tcslen(pstr) : cchMax);
 5         if( cchMax < MAX_LOCAL_STRING_LEN ) {
 6             if( m_pstr != m_szBuffer ) {
 7                 free(m_pstr);
 8                 m_pstr = m_szBuffer;
 9             }
10         }
11         else if( cchMax > GetLength() || m_pstr == m_szBuffer ) {
12             if( m_pstr == m_szBuffer ) m_pstr = NULL;//若指向m_szBuffer,不能將其釋放,先指向NULL
13             m_pstr = static_cast<LPTSTR>(realloc(m_pstr, (cchMax + 1) * sizeof(TCHAR)));
14         }
15         _tcsncpy(m_pstr, pstr, cchMax);
16         m_pstr[cchMax] = _T('\0');
17     }

Assign這個函數設計的十分精妙,很多地方都用到,它主要用於重新賦值操作。cchMax表示截取pstr的范圍[0,cchMax),若m_szBuffer長度足以存儲,則直接賦值,把指針指過去;若不夠長,重新申請內存賦值

 1 int CDuiString::Replace(LPCTSTR pstrFrom, LPCTSTR pstrTo)
 2     {
 3         CDuiString sTemp;
 4         int nCount = 0;
 5         int iPos = Find(pstrFrom);
 6         if( iPos < 0 ) return 0;
 7         int cchFrom = (int) _tcslen(pstrFrom);
 8         int cchTo = (int) _tcslen(pstrTo);
 9         while( iPos >= 0 ) {
10             sTemp = Left(iPos);
11             sTemp += pstrTo;
12             sTemp += Mid(iPos + cchFrom);
13             Assign(sTemp);
14             iPos = Find(pstrFrom, iPos + cchTo);
15             nCount++;
16         }
17         return nCount;
18     }

替換字符串,首先查找是否存在需要替換的字符串,沒有則直接返回0,存在的話,將其分為三段,中間一段替換,用sTemp儲存,再重新賦值sTemp,如此往復替換所有的pstrFrom。

 1 int CDuiString::Format(LPCTSTR pstrFormat, ...)
 2     {
 3         LPTSTR szSprintf = NULL;
 4         va_list argList;
 5         int nLen;
 6         va_start(argList, pstrFormat);
 7         nLen = ::_vsntprintf(NULL, 0, pstrFormat, argList);
 8         szSprintf = (TCHAR*)malloc((nLen + 1) * sizeof(TCHAR));
 9         ZeroMemory(szSprintf, (nLen + 1) * sizeof(TCHAR));
10         int iRet = ::_vsntprintf(szSprintf, nLen + 1, pstrFormat, argList);
11         va_end(argList);
12         Assign(szSprintf);
13         free(szSprintf);
14         return iRet;
15     }

Format函數用於格式化字符串,與常用的printf類似。具體實現來看看,va_list argList, 這個是什么東東,一開始確實沒見過,看看其定義

typedef char *  va_list;原來是char*,它是用於指向可變參數的,va_start(argList,pstrFormat)后,argList指向第一個可變參數,接下來調用_vsntprintf(NULL,0,pstrFormat,argList),最后將格式化后的字符串重新賦值回去即可。

想了解關於va_list 可參考這里:http://blog.csdn.net/edonlii/article/details/8497704

其實難點也並非很難,只是一些需要注意的小問題總是會被自己忽略,看別人寫的好的代碼還是挺有收獲的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM