3.vector实现字符串类
??3.vector實現(xiàn)字符串類
? 本章前言:
??? 身為土生土長的中國程序員,你肯定要用unicode來編寫程序。但是由wchar_t數(shù)組實現(xiàn)的字符串準(zhǔn)確點說應(yīng)該叫字符數(shù)組,但它在使用時比較繁瑣,而且容易出現(xiàn)數(shù)組越界和字符串結(jié)尾不為0的錯誤。 為了方便實現(xiàn)字符串相關(guān)的功能,DND引擎抽象了String類,其底層是vector<wchar_t>。為什么不使用std::string呢,因為其不能定制化功能,例如+操作符直接連接兩個字符串、使用sprintf格式化生成字符串等等。
? 目標(biāo)要點總結(jié):
1.? 實現(xiàn)字符串類
2.? 類似基礎(chǔ)類型的使用方式
? 最終效果:
??? 例如下面這樣使用:
??? Stringstr=String(L”Hello”)+ L” ” + L”DND!”;//str等于Hello DND!
??? 具體的接口可以查看頭文件中的注釋。
??? class StrVector;
??? class DLL_APIString
??? {
??? public:
??????? //==================構(gòu)造、析構(gòu)、操作符========================
??????? String();//空串
??????? String(constchar* str);//字符數(shù)組
??????? String(constwchar_t* wcs);//寬字符數(shù)組
??????? String(wchar_twc);//寬字符
??????? ~String();//析構(gòu)
??????? String(constString& b);//復(fù)制構(gòu)造
??????? //String(const unsigned b);
??????? String(constint b);//數(shù)字構(gòu)造
??????? String(wchar_tch, unsigned len);//填充len個 ch
??????? String(StrVector*);//strvector構(gòu)造
??????? String& operator=(constString& b);//=號重載
??????? String operator+(constString& b) const;//連接
??????? bool operator==(constString& b) const;//相同
??????? bool operator<(constString& b) const;//小于
?
??????? unsigned Get_Length() const;//返回長度
??????? //==================轉(zhuǎn)化==================
??????? const wchar_t*Get_Wcs() const;
??????? void Get_Wide_Char_Str(wchar_t* target, unsigned max_len) const;//獲得寬字符數(shù)組
??????? void Get_Multi_Byte_Str(char* target, unsigned max_len) const;//獲取字符數(shù)組
??????? int Get_Int();//返回int
?
??????? void Clear();//設(shè)為空串
??????? void Pop();//去掉結(jié)尾
???????
??????? //==================查找==================
??????? unsigned Find_End(wchar_t wc);//查找最后一個
??????? unsigned Find_Str(const String&str);//查找字符串位置,返回-1代表不存在
??????? unsigned Find_N(wchar_t wc,unsigned N);//查找第n個要查找的字符
??????? unsigned Get_Char_Count(wchar_t ch);//返回某字符出現(xiàn)的個數(shù)
??????? String Get_Str(unsigned begin, unsigned end);//返回區(qū)間內(nèi)的字符串
??????? //==================刪除==================
??????? void Cut(unsigned begin,unsigned end);//去掉區(qū)間內(nèi)的字符串 [b, e]
??????? void Cut_Tail(unsigned i);//去掉i位置后的包括i
??????? void Cut_Head(unsigned i);//去掉i位置前的包括i
??????? void Cut_Head_Str(const String& str);//去除頭部字符串
???????
???????
??????? //==================修改==================
??????? void Delete_Char(unsigned i);//i位置刪除一個字符
??????? void Insert_Char(unsigned i, wchar_t ch);//i位置前插入一個字符,第一個字符位置為0
??????? void Replace_Char(wchar_t source, wchar_t target);//替換某個字符
???????
??????? unsigned Split(wchar_t wc,String* strs, unsigned max_size);//返回實際分隔后的字符串個數(shù)。例如 a;b;返回 a b 2
??????? static StringFormat(unsignedmax_size, const wchar_t* format, ...);//max size不包含結(jié)束符
??? private:
??????? StrVector* p;
??????? void _init();
??????? void _copy(const wchar_t*wcs);
??? };?
???
前題簡要:
??? 無。
具體實現(xiàn):
??? 由于需要生成動態(tài)鏈接庫,所以要在導(dǎo)出的接口中隱藏掉vector<wchar_t>類,可以使用void指針保存指向?qū)嶋H的vector<wchar_t>對象的地址,然后在接口定義中進行指針強轉(zhuǎn)。但這樣代碼看上去過于雜亂,有更好的方式實現(xiàn)。在前面的頭文件可以看到StrVector類的聲明:
??? class StrVector;
??? 這樣就能在String類中聲明StrVector指針類型的變量p。在cpp中才實現(xiàn)了StrVector的定義,StrVector的定義如下:
??? class StrVector :public vector<wchar_t>
??? {
??? public:
??????? StrVector(vector<wchar_t>*p) :
??????????? vector<wchar_t>(*p){}
??????? StrVector(){}
??? };
??? 這樣String類的指針p就能直接訪問基類vector<wchar_t>的成員。p指針的初始化交給String類的構(gòu)造函數(shù),構(gòu)造函數(shù)會調(diào)用_init()。
??? void String::_init()
??? {
??????? p = newStrVector;
??? }
??? 例如默認(rèn)構(gòu)造函數(shù)會構(gòu)造一個空串,如下:
??? String::String()
??? {
??????? _init();
??? }
??? 使用char字符數(shù)組構(gòu)造:
??? String::String(constchar* str)
??? {
??????? _init();//初始化
?
??????? unsigned len =strlen(str) + 1;//字符串長度
??????? wchar_t* wcs =new wchar_t[len];//分配臨時內(nèi)存
??????? //multi_byte轉(zhuǎn)wide_char(即char數(shù)組轉(zhuǎn) wchar_t)
??????? MultiByteToWideChar(CP_ACP,NULL, str, -1, wcs, len);
??????? //設(shè)置vector最大長度為len
??????? p->reserve(len);
??????? //復(fù)制字符串
??????? _copy(wcs);
??????? delete[] wcs;
??? }
??? 其中首先獲取字符串長度,然后分配足夠的內(nèi)存大小(加1放下結(jié)束符)。然后調(diào)用MultiByteToWideChar函數(shù)將char數(shù)組轉(zhuǎn)換至wchar_t數(shù)組,再預(yù)先設(shè)置vector<wchar_t>的最大長度。調(diào)用_copy將數(shù)據(jù)從buffer復(fù)制到vector,最后釋放buffer。
??? 連接字符串的實現(xiàn)如下,首先復(fù)制構(gòu)造一個臨時對象str,然后在尾部插入b字符的所有字符,最后再返回拷貝:
??? String String::operator+(constString& b) const
??? {
??????? String str = *this;
??????? str.p->insert(str.p->end(),b.p->begin(),b.p->end());
??????? return str;
??? }
??? 有很多系統(tǒng)函數(shù)、庫函數(shù)都要求以const wchar_t*類型作為函數(shù)參數(shù),讓String快速的返回字符串首地址很有必要。由于String的vector不包含結(jié)束符,所以需要擴容尾部為0,但長度仍然不變。實際的實現(xiàn)如下:
??? const wchar_t*String::Get_Wcs()const
??? {
??????? p->push_back(0);
??????? wchar_t * temp = &(*p)[0];//保證0下標(biāo)不越界
??????? p->pop_back();
??????? return temp;
??? }
??? 比如在排序兩個字符串的時候就用到了Get_Wcs,如下:
??? bool String::operator<(constString& b) const
??? {
??????? return wcscmp(Get_Wcs(),b.Get_Wcs()) < 0;
??? }
??? sprintf函數(shù)用來格式化字符串非常好用,所以有必要封裝類似的接口,封裝之后可以這樣生成一個字符串:
??? String str =String::Format(256,L"FPS:%d dt:%f", fps, dt);
??? Format是一個靜態(tài)變長參數(shù)函數(shù),使用方式類似于sprintf,第一個256是指臨時buffer的最大長度,具體實現(xiàn)如下:
??? String String::Format(unsignedmax_size, const wchar_t* format, ...)
??? {
??????? wchar_t* wcs =new wchar_t[max_size + 1];
??????? va_list args;
??????? va_start(args,format);
?
??????? vswprintf_s(wcs,max_size + 1, format,args);
?
??????? va_end(args);
?
??????? String ret =String(wcs);
??????? delete[] wcs;
??????? return ret;
??? }
??? 有關(guān)查找、刪除、編輯功能的實現(xiàn)這里就不貼了,很簡單,使用vector的接口很好實現(xiàn)。作者以前實現(xiàn)的String是基于wchar_t數(shù)組的,由自己慢慢的添加接口而成(手動寫每個算法真的很麻煩)。最近規(guī)范下了命名,并換用了vector<wchar_t>實現(xiàn),一天就完成了,所以標(biāo)準(zhǔn)庫還是好用啊!
?
作者:略游
日期:17-06-20
QQ:1339484752
總結(jié)
以上是生活随笔為你收集整理的3.vector实现字符串类的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2.创建适合游戏的窗口和消息循环
- 下一篇: 4.使用pnglib读写png图片