Conversion 库由四个转换函数组成,分别提供了更好的类型安全性(polymorphic_cast), 更高效的类型安全防护(polymorphic_downcast), 范围检查的数字转换(numeric_cast), 以及文字转换(lexical_cast)。这些类cast函数共享C++转型操作符的语义。与C++的转型操作符一样,这些函数具有一个重要的品质,类型安全性,这是它们与C风格转型的区别:它们明确无误地表达了程序员的意图[2]。我们所写的代码的重要性不仅在于它可以正确执行。更重要的是代码可否清晰地表达我们的意图。这个库使得我们可以更容易地扩展我们的C++词汇表。
polymorphic_cast:
头文件: "boost/cast.hpp"
C++中的多态转型是用 dynamic_cast来实现的。dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。 在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的。使用static_cast进行向下转换通常是危险的。dynamic_cast有一个有时会导致错误代码的特性,那就是它对于所使用的不同类型会有不同的行为。在用于一个引用类型时,如果转型失败,dynamic_cast 会抛出一个异常。这样做的原因很简单,因为C++里不允许有空的引用,所以要么转型成功,要么转型失败而你获得一个异常。当然,在 dynamic_cast 用于一个指针类型时,失败时将返回空指针。无法完成的转换会返回0(指针)或者抛出异常(引用)。
dynamic_cast的这种对指针和引用类型的不同行为以前被认为是一个有用的特性,因为它允许程序员表达他们的意图。典型地,如果转型失败不是一种逻辑错误,就使用指针转型,如果它确是一种错误,就使用引用转型。不幸的是,两种方法之间的区别仅在于一个*号和一个&号,这种细微的差别是不自然的。如果想把指针转型失败作为错误处理,该怎么办?为了通过自动抛出异常来清楚地表达这一点,也为了让代码更一致,Boost提供了polymorphic_cast. 它在转型失败时总是抛出一个 std::bad_cast 异常。
必须记住,其它人将要维护我们写的代码。这意味着我们必须确保代码以及它的意图是清晰并且易懂的。这一点可以通过注释部分地解决,但对于任何人,更容易的方法是不需加以说明的代码。当(指针)转型失败被认为是异常时,polymorphic_cast 比dynamic_cast更能清晰地表明代码的意图,它也导致更短的代码。如果转型失败不应被认为是错误,则应该使用dynamic_cast,这使得dynamic_cast的使用更为清楚。仅仅使用 dynamic_cast 来表明两种不同的意图很容易出错,而不够清楚。抛出异常与不抛出异常这两个不同的版本对于大多数程序员而言太微妙了。
何时使用 polymorphic_cast 和 dynamic_cast:
-
当一个多态转型的失败是预期的时候,使用 dynamic_cast<T*>. 它清楚地表明转型失败不是一种错误。
-
当一个多态转型必须成功以确保逻辑的正确性时,使用 polymorphic_cast<T*>. 它清楚地表明转型失败是一种错误。
-
对引用类型执行多态转型时,使用 dynamic_cast.
numeric_cast:
整数类型间的转换经常会产生意外的结果。例如,long 可以拥有比short更大范围的值,那么当从 long 赋值到short 并且 long的数值超出了 short的范围时会发生什么?答案是结果是由实现定义的(比"你不可能明确知道"好听一点的说法)。相同大小整数间的有符号数到无符号数的转换是好的,只要有符号数的数值是正的,但如果有符号数的数值是负的呢?它将被转换为一个大的无符号数,如果这不是你的真实意图,那么就真的是一个问题了。numeric_cast 通过测试范围是否合理来确保转换的有效性,当范围超出时它会抛出异常boost::bad_numeric_cast。
想查看你的系统上的类型大小,可以使用 sizeof(T) 或 std::numeric_limits<T>::max() 和 std::numeric_limits<T>::min()。
numeric_cast 提供了算术类型间高效的范围检查转换。在目标类型可以持有所有源类型的值时,使用 numeric_cast没有额外的效率代价。它只在目标类型仅能表示源类型的值的子集时有影响。当转换失败时,numeric_cast 通过抛出一个 bad_numeric_cast异常来表示失败。对于数值类型间的转换有很多复杂的规则,确保转换的正确性是很重要的。
以下情况时使用 numeric_cast:
-
在无符号与有符号类型间进行赋值或比较时
-
在不同大小的整数类型间进行赋值或比较时
-
从一个函数返回类型向一个数值变量赋值,为了预防该函数未来的变化
lexical_cast:
是用于字符串与其它类型之间的字面转换的一个可重用及高效的工具。它是功能性和优雅性的结合,是杰出程序员的伟大杰作。 不要在需要时实现小的转换函数,更不要在其它函数中直接插入相关逻辑,应该使用象 lexical_cast 这样的泛型工具。它有助于使代码更清晰,并让程序员专注于解决手上的问题。
std::string s="42";
int i=boost::lexical_cast<int>(s);
float f=3.14151;
s=boost::lexical_cast<std::string>(f);
// 失败的转换
s="Not an int";
try {
i=boost::lexical_cast<int>(s);
}
catch(boost::bad_lexical_cast& e) {
// 以上lexical_cast将会失败,我们将进入这里
}
以下情况时使用lexical_cast:
-
从字符串类型到数值类型的转换
-
从数值类型到字符串类型的转换
-
你的自定义类型所支持的所有字面转换