1. 程式人生 > >條款2~3:GotW#29 不區分大小寫的string

條款2~3:GotW#29 不區分大小寫的string

編寫一個與標準的std::string類完全相同ci_string類,但是它與通常提供的擴充套件函式stricmp一樣是不區分大小寫的。ci_string應用能夠如下使用:

ci_string s("AbCde");
//不區分大小

assert(s == "abcde");
assert(s == "ABCDE");

assert(strcmp(s.c_str(),"AbCdE") == 0);
assert(strcmp(s.c_str(),"abcde") == 0);

C++標準庫中,string的標頭檔案宣告如下:

typedef basic_string<char> string;

template<class charT,
		 class traits = char_traits<charT>,
		 class Allocator = allocator<charT> >
class basic_string;

函式中,char_traits定義了字串之間的相互作用和比較的方式;char_traits模板提供了名為eq()和lt()的字串比較函式,提供了compare()和find()函式來比較和查詢字串,如果我們想這些函式有不同的行為表現,所要做的只是提供一個不同的char_traits模板:

struct ci_char_traits : public char_traits<char>
{
	static bool eq(char c1,char c2)
	{
		return toupper(c1) == toupper(c2);
	}

	static bool lt(char c1,char c2)
	{
		return toupper(c1) < toupper(c2);
	}
	
	static int compare(const char* s1,const char* s2,
					   size_t n)
	{
		return memicmp(s1,s2,n);//linux可以使用strncasecmp替代
	}
	
	static const char* find(const char* s,int n,char a)
	{
		while(n-- > 0 && toupper(*s) != toupper(a))
		{
			++s;
		}
		return s;
	}
}

typedef basic_string<char,ci_char_traits> ci_string;

我們重新定義了一個ci_string,它的操作非常像標準的string,只是使用了ci_char_traits替代了char_traits<char>以使用特別的規則。

這次GotW揭示了basic_string模板工作的原理以及實現使用上的靈活性。

問題:

1.使用這種方式從char_traits<char>繼承ci_char_traits是安全的麼?

繼承是安全的,但是這裡不能多型的使用ci_char_traits。

2.為什麼如下的程式碼編譯失敗呢(由於C++的改進,現在可以編譯通過,並正常執行。)?

ci_string s = "abc";
cout << s << endl;

因為在C++標準庫中,base_string的operator<<宣告如下(C++標準中已將base_ostream<charT,traits>& os改為“ostream&”,所以沒問題了):

template<class charT,char traits,class Allocator>
basic_ostream<charT,traits>&
operator <<(basic_ostream<charT,traits>& os,
			const basic_string<charT,traits,Allocator& str>);

有兩個解決方法:定義ci_string自己的輸入/輸出流函式,或使用".c_str()":

cout << s.c_str() << endl;

3.當在標準string物件和ci_string物件間使用其他的(如+,+=,=)時,例如:

sting a = "aaa";
ci_string b = "bbb";
string c = a + b;

解決方法還是定義自己的這些操作函式,或者新增使用“.c_str()”:

cout << c = a + b.c_str();