教授 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++功力越深,写出来的代码越抽象,越难以理解,但越灵活,越简洁。当然,代码写得越简洁,也有老板觉得你工作偷懒的危险^_^。
评论