zoukankan      html  css  js  c++  java
  • 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('');
    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

    其实难点也并非很难,只是一些需要注意的小问题总是会被自己忽略,看别人写的好的代码还是挺有收获的。

  • 相关阅读:
    调试一个 Bus error 错误
    推荐10个我在用的Chrome浏览器插件
    六个让你的Ubuntu系统提速的方法
    6个可以隐藏运行bat,浏览器等程序的方法
    Windows下5个简单快速加密文件的方法
    如何获取与安装你需要的android 应用
    一款免费的.NET智能持续测试运行工具——MightyMoose
    给 mysql 系统表加上 trigger
    2011百度数据挖掘研发工程师实习生笔试面试题
    Linux常用操作命令整理
  • 原文地址:https://www.cnblogs.com/george-cw/p/5347755.html
Copyright © 2011-2022 走看看