教授 C++,如果还使用 Hello World 的例子作为入门,那就弱爆啦!它只能告诉你不要用 printf,要用 cout。但是,为什么?这两个有什么区别?cout 就代表了 C++吗?我们还是整点有技术含量的吧。
问题:编写“字符串与数值互相转换”的函数。
C 语言风格
/* C 风格编码*/#include <cstdlib>#include <cstdio>using namespace std; void value2str(int value){ char str[30] = {'\0'}; itoa(value, str, 10); //C标准库有这个函数么? printf("string : %s\n", str);} void str2value(char* str){ int value = atoi(str); printf("value : %d\n", value); }
复制代码
这种方式至少存在如下几个问题:
(1)字符串的长度有限制;
(2)必须预先定义一个数组存储字符串,使用数组也有内存泄露的危险;
(3)调用 C 的库函数,受制于函数参数约束。
C++风格
/* C++ 风格编码*/#include <string>#include <sstream> using namespace std; /* 整型-> 字符串*/string ValueToStr(int value){ ostringstream ost; ost << value; return ost.str();} /* 字符串-> 整型*/int StrToValue(char* str){ string strValue(str); //转换为string istringstream osValue; osValue.str(strValue); //得到istrstream int value; osValue >> value; //得到数值 return value;}
复制代码
使用 C++的 string stream,可处理变长字符串,无内存泄露之虞。但无扩展性,因为如果要求是 double 类型与字符串互相转换,需要再写两个重载函数。
函数模板
/* 函数模板*/template <typename T>string Value2Str(T value){ ostringstream ost; ost << value; return ost.str();} template<typename T> T Str2Value(char* str){ string strValue = str; //转换为string istringstream osValue; osValue.str(strValue); //得到istrstream T value; osValue >> value; //得到数值 return value;}
复制代码
使用 template,可处理各种数据类型和字符串的转换,用户代码中调用了哪个类型,编译器才会编译相应的目标代码,灵活性很大。
当然这个例子中还要考虑字符串转换出来的数值,不能超出数据类型的最大值,这个不是讲述的重点。重点在于,通过这几种风格的代码,展现一下为了解决一个简单的问题,在 C++中我们到底能有多少选择。
我是因为平时编写代码时需要用到上述功能,用的多了,就慢慢总结出了这么一套做法,当然比较粗糙,下面来看个不粗糙的。
boost 实现
某日翻阅 boost 的文档,发现 boost 里居然已经提供了类似功能的 lexical_cast。
其定义形式如下:
namespace boost{ class bad_lexical_cast; template<typename Target, typename Source> Target lexical_cast(const Source& arg);}
复制代码
也是采用模板的形式定义的一套东西,用于 string 和数值的相互转换。简单的使用例子如下:
#include <boost/lexical_cast.hpp> //下面的例子把一系列数字作为命令行参数:int main(int argc, char * argv[]){ using boost::lexical_cast; using boost::bad_lexical_cast; std::vector<short> args; while(*++argv) { try { args.push_back(lexical_cast<short>(*argv)); } catch(bad_lexical_cast &) { args.push_back(0); } } //...} //下面的例子使用字符串表达式来表示数字:void log_message(const std::string &);void log_errno(int yoko){ log_message("Error " + boost::lexical_cast<std::string>(yoko) + ": " + strerror(yoko));}
复制代码
和我的设计具有相同的一个缺陷,浮点数的精度无法控制。更详细的内容,请参见 boost 库的相关文档。
结语
从上面的例子我们可以看出,同样是使用 C++语言,不同的编程风格写出来的代码却相差很大。C++功力越深,写出来的代码越抽象,越难以理解,但越灵活,越简洁。当然,代码写得越简洁,也有老板觉得你工作偷懒的危险^_^。
评论