C++标准库提供了字符串类std::string
,这个类包含了字符串常用的操作,包括实现了operator==
来实现字符串的比较,但这里的比较是区分大小写的。那么在不使用操作系统提供的不区分大小写函数的情况下,如何方便的利用std::string
来实现一个区分大小写的类呢?这里的奥妙就在于巧妙地运用了char_traits<char>
这个字符串的辅助模板类。
首先std::string
的定义如下:
typedef basic_string<char, char_traits<char>, allocator<char>> string
typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>> wstring
所以我们可以以char_traits<char>
(这里仅讨论窄字符串)为基类,重新定义其中相关的字符比较函数,其它的不变,从而可以方便的实现不区分大小写的字符串类。
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);
}
static const char* find( const char* s, int n, char a )
{
while( n-- > 0 && toupper(*s) != toupper(a))
{
++s;
}
return n >= 0 ? s : 0;
}
};
typedef basic_string<char, ci_char_traits> ci_string;
以上实现比较讨巧,但不得不说虽然这样可以实现,但还是会有几个问题,如下:
1. ci_char_traits
继承自char_traits<char>
,但并不表示这两者之间是一种 is-a
关系,并且这两个类中的所有函数都是static
的,所以两者间也不存在多态的这种关系。
2. 当 ci_string
和string
去比较或者相加时会有问题,这个时候要么提供相应的比较或者相加函数,要么取两者的.c_str()
来取得内部的字符串指针。
3. 利用cout
来输出std::string
是支持的,因为c++标准库里有这样的定义:
template<class char, class traits, class Allocator>
basic_ostream<char, traits>&
operator<<(basic_ostream<char, traits>& os,
const basic_string<char, traits, Allocator>& str)
而 cout
的类型则是basic_ostream<char, char_traits<char> >
所以 cout
是无法输出ci_string类型的,当然有一种比较简单的输出方式是用输出 .c_str()
的方式。