程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 編寫一個STL中的CString類

編寫一個STL中的CString類

編輯:關於VC++

STL英文是Standard Template Library,也就是我們常說的C++標准模板庫,。該標准庫於1998年被正式納入C++標准,給全世界的C++程序員帶來了福音。最讓我們興奮的應該是它的跨平台性,使得你在WINDOW,UNIX ,LINUX等操作系統上面用標准C++編寫的程序不用修改即可移植。(當然要有C++的編譯器)。

現在的編譯器雖然對標准C++支持程度不同,單總體上還是很好。WINDOWS平台的VC ,BC,Linux/UNIX平台的g++都是一流的編譯器,都支持STL。而且STL是有源代碼的,你可以擴展增加,避開這些微小的不同。

說到STL首先要說的當然是字符串處理類std::string,這可能是一個程序員使用最多的一個類,它的功能強大,使用非常方便。但習慣於用VC的CString開發的編程人員會感到有點不方便。幸運的是這個不方便可以很容易的解決,方法就是對標准的字符串類std::string進行包裝,生成一個類似Cstring的類,我把它命名為Xstring。

下面就從Format函數說起,這可能是大部分人最希望用到的:

本函數是一個變參函數,對參數不定的函數其各式如下:

int Format(const char* pstrFormat, ... )

其中pstrFormat是格式串,三個點代表所有的參數。格式中的每個格式和後面的參數必須相對應,否則函數的執行會出現意想不到的結果;當然過多的參數將被忽略。格式分為簡單字符和轉換規范字符兩類。具體格式規范有如下格式:

%[flags] [width] [.precision] [{h | l | I64 | L}]type

flags是標志字符,輸出對齊,尾零,數值符號,進制數(八或十六)

width是寬度規范符,填補空格或0的個數

precision是精度規范符,打印字符最多個數,對於整數值,為最少數字個數

h短整型數的輸出

I長整型數的輸出

I64為64位的整型輸出

如果你對格式還不清楚,請參考有關printf的格式資料。

對不定參數的處理也很特殊,要使用下面的幾個函數

先聲明一個變量va_list argList;

va_start(argList,pstrFormat);
int cnt = vsprintf(buff, pstrFormat, argList);
va_end(argList);

這樣就把格式化後的結果保存在buff字符串中了。

然後最重要的就是計算這個buff有多大,如果大了就有內存浪費,小了完不成任務,所以要根據格式來動態計算,然後動態的開辟內存空間。就用一個循環來把格式串中的每一個字符讀出來分別處理。先初始化一個長度變量nMaxLen =0;

for (const char * p = pstrFormat; *p != '\0';p++ )

如果讀出來的不是'%'或是'%%'則長度加一。

if (*p != '%' || *(++p) == '%')
{
nMaxLen += 1;
continue;
}

如果前一個字符是'%',則讀取格式,如果是'#'則長度加2,來為'0x'預留空間;如果是'*',則讀緊跟著的一個整數,得到指定的寬度;其他的'+'、'-'、' '、'0'等字符主要是填充用,忽略長度。

for (; *p != '\0'; p ++)
{
if (*p == '#')
nMaxLen += 2; // 處理 '0x'
else if (*p == '*')
nWidth = va_arg(argList, int); //如:'%5f' 中的5
else if (*p == '-' || *p == '+' || *p == '0'|| *p == ' ')
; //忽略該符號
else // 不是標志字符就退出循環
break;
}

如果下一個字符是'.'則忽略去讀取其後面一個字符,如果是'*'則也要讀出其後的寬度,來計算精度。

if (*p == '*')
{
nPrecision = va_arg(argList, int);
p ++;
}
else
{
nPrecision = atoi(p);
for (; *p != '\0' && isdigit(*p); p ++)
;
}

接下來處理字符如果是'h'、'l'、'I'、'F'、'N'等,則忽略計算長度。

如果讀取字符是'c'、'C'則長度加上2(考慮寬字符的情況);如果讀取的是's'、'S'則要計算參數中給的字符串的寬度。

switch (*p)
{
case 'c':
case 'C':
nItemLen = 2;
va_arg(argList, char);
break;
case 's': // 字符串
case 'S':
nItemLen = strlen(va_arg(argList, const char*));
nItemLen = ((1) > (nItemLen)) ? (1) : (nItemLen);//如果是空串就使用1 即保存'\0'
break;
}

如果讀出的字符是'd'、'i'、'u'、'x'、'o','e'、'f'、'G'、'g'等,則長度加上對應的數值型的長度,當然最好使用sizeof計算,使得具有更好的移植能力。

case 'd':
case 'i':
case 'u':
case 'x':
case 'X':
case 'o':
va_arg(argList, int);
nItemLen = 32;

在for循環體的最後當然不要忘了把長度累計nMaxLen += nItemLen;當循環結束時,長度的計算也就完成了。

For循環結束時調用va_end(argList);

下面就可以開辟恰當的內存空間,來保存你的格式串。

char* ch = new char[nMaxLen+1];

有了空間再重新接收參數就可以了。

va_start(argList, pstrFormat);
vsprintf(ch, pstrFormat, argList);
va_end(argList);

最後不要忘了把空間加到std::string中,可以直接調用append函數:

this->append(ch);

然後釋放你的內存空間

delete[] ch;

其他的函數可以用std::string中的相對應的功能包裝即可,下面就再寫一個MakeUpper函數,它也是CString中的。

void MakeUpper()
{
std::transform(this->begin (), \
this->end (),this->begin (),\
toupper);
}

是不是很容易呢,希望本文能起到拋磚引玉的作用,給你使用STL帶來方便。

以上的程序編碼在VC和g++中均可使用。本人曾用XString 類替代了一個用MFC編寫的項目中的所有的CString類 ,使得它順利的用G++編譯通過。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved