DuiLib 源码分析之CDuiString
Posted 这么近_那么远
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
其实难点也并非很难,只是一些需要注意的小问题总是会被自己忽略,看别人写的好的代码还是挺有收获的。
以上是关于DuiLib 源码分析之CDuiString的主要内容,如果未能解决你的问题,请参考以下文章