时间:2014.04.23
地点:基地
-----------------------------------------------------------------------
很多时候我们需要大小写不敏感的字符串。比如标准库中的扩展啊比较函数stricmp(),当使用它对字符串进行比较时,大小写是一视同仁。
-----------------------------------------------------------------------
假定现在要求编写一个和string类功能相当的类ci_string,但对大小写不敏感。怎么做?
-----------------------------------------------------------------------
先来看看string的头文件,有如下代码:
typedef basic_string<char> string;也就是说,string其实质并不是一个类,而是一个由模板生成的实例。在看basic_string<>的声明
template<class charT, class traits=char_traits<charT> class Allocator=allocator<charT>> class basic_string;即basic_string模板含有3个类型参数,string的实际含有是basic_string<char,char_traits<char>,allocator<char>>。在这里,char_traits定义了字符之间的交互方式,包括字符串比较。basic_string提供了有用的字符串比较函数,这些比较函数都是建立在char_traits模板提供的字符比较函数之上的,注意这里的字符比较函数。比如char_traits模板中提供了字符比较函数eq()和lt()用于比较两个字符串是否相等,或者小于,还有comare()和finde()。
在我们描述的问题当中,在现在看来,其实就是想改变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); } static const char* find(const char*s, int n, char a) { while (n-->0 && toupper(*s) != toupper(a)) ++s; return n >= 0 ? s : 0; } };这个类继承自char_traits<char>,于是该有的功能都会有,我们只是想改变功能的行为。最后利用这个类实例化模板:
typedef basic_string<char,ci_char_traits> ci_string;
现在你就可以像使用标准库中的string类一样使用ci_string了。只是对大小写不敏感而已,在这里,并没有对该类做很大的手脚,而对basic_string本身来说,根本没有改动,这就是程序的扩展性,这种思想值得学习。
另外值得说明的是,在这里,我们是将大小写敏感作为比较函数的属性,其实对于对象本身而言还是有区别的,将大小写作为比较函数的属性有这样一个好处,比如我们在对string和ci_string进行比较操作时:
string a="liu"; ci_string="LIU"; if(a==b) ......当然之间对于两种不同类型是不能operator==()操作的,注意这里string和ci_string是不同的类型,假定我们实现了这样一个操作,那么想要的意思就是:当有任何一个操作数是大小写不敏感的,那么这个比较运算符就应该也是不敏感的。但这样做,将大小写不敏感作为比较运算符的属性会使得语义并不那么清晰,特别是比C字符串做比较时,比如:
if(a=="text")在这种情况下,将大小写敏感作为对象的属性会更有用。
-----------------------------------------------------------------------
在这一小节中,学到的东西有:
1. basic_string模板在实际中非常有用,因为它提供了良好的扩展性,我们只需修改 char_traits<T>的部分行为就可以到达很好的效果。
2. struct和class在C++中几乎是无区别的,有那么一点点,关于默认成员时public和private的,你懂的。
3.我们可以用模板实例化出一个想要的类,并配上自定义的类名
比如这句:
typedef basic_string<char,ci_char_traits> ci_string;