c++小技巧(三)更好的类型转换implicit_cast和down_cast

在C++中有四种类型转换

1.static_cast:这个是最常用的类型转换,凡是C++隐式执行的类型转换都可以用static_cast显式完成。在隐式转换时有时编译器会有警告信息,但是显示转换(使用static_cast)就不会有。static_cast还会进行一些基础的类型检查,能在编译期发现错误。

float f=0;
int a=(int)f; //强行转换,可能会有警告
int a=static_cast<int>f; //使用static_cast消除警告

2.const_cast:从名字可以看出和const有关,这个转换的作用是去除或添加const特性,它可以将一个const变量转换为非const变量,或将一个非const变量转换为const变量。
3.dynamic_cast:dynamic_cast依赖于RTTI信息,在转换时,dynamic_cast会检查转换的source对象是否真的可以转换成target类型,这种检查不是语法上的,而是真实情况的检查。被转换的类型必须是多态(即有虚函数)。
4.interpret_cast:interpret意思为重新解释,意思为将数据的二进制格式重新解释,它依赖机器。

implicit_cast和down_cast

  在muduo有另外两个转换implicit_cast和down_cast(看注释应该是google的代码)。什么时候用,为什么用基本上都在注释里面了,可以重点看下。

// Use implicit_cast as a safe version of static_cast or const_cast
// for upcasting in the type hierarchy (i.e. casting a pointer to Foo
// to a pointer to SuperclassOfFoo or casting a pointer to Foo to
// a const pointer to Foo).
// When you use implicit_cast, the compiler checks that the cast is safe.
// Such explicit implicit_casts are necessary in surprisingly many
// situations where C++ demands an exact type match instead of an
// argument type convertable to a target type.
//
// The From type can be inferred, so the preferred syntax for using
// implicit_cast is the same as for static_cast etc.:
//
//   implicit_cast(expr)
//
// implicit_cast would have been part of the C++ standard library,
// but the proposal was submitted too late.  It will probably make
// its way into the language in the future.
template<typename To, typename From>
inline To implicit_cast(From const &f)
{
  return f;
}
// When you upcast (that is, cast a pointer from type Foo to type
// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts
// always succeed.  When you downcast (that is, cast a pointer from
// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because
// how do you know the pointer is really of type SubclassOfFoo?  It
// could be a bare Foo, or of type DifferentSubclassOfFoo.  Thus,
// when you downcast, you should use this macro.  In debug mode, we
// use dynamic_cast<> to double-check the downcast is legal (we die
// if it's not).  In normal mode, we do the efficient static_cast<>
// instead.  Thus, it's important to test in debug mode to make sure
// the cast is legal!
//    This is the only place in the code we should use dynamic_cast<>.
// In particular, you SHOULDN'T be using dynamic_cast<> in order to
// do RTTI (eg code like this:
//    if (dynamic_cast(foo)) HandleASubclass1Object(foo);
//    if (dynamic_cast(foo)) HandleASubclass2Object(foo);
// You should design the code some other way not to need this.

template<typename To, typename From>     // use like this: down_cast(foo);
inline To down_cast(From* f)                     // so we only accept pointers
{
  // Ensures that To is a sub-type of From *.  This test is here only
  // for compile-time type checking, and has no overhead in an
  // optimized build at run-time, as it will be optimized away
  // completely.
  if (false)
  {
    implicit_cast(0);
  }

#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI)
  assert(f == NULL || dynamic_cast(f) != NULL);  // RTTI: debug mode only!
#endif
  return static_cast(f);
}

  在up_cast时应该使用implicit_cast替换static_cast,因为后者比前者要安全,以一个例子说明,在菱形继承中,最底层的对象可以转换为中层对象

#include
#include

class Top{};
class MiddleA:public Top{};
class MiddleB:public Top{};
class Bottom:public MiddleA,public MiddleB{};

void Function(MiddleA& A)
{
    std::cout<<"MiddleA Function"<<std::endl;
}
void Function(MiddleB& B)
{
    std::cout<<"MiddleB Function"<<std::endl;
}
int main()
{
    Bottom bottom;
    Function(bottom);
    return 0;
}

  这时如果编译,就会出现错误,因为在调用函数Function时,bottom既可以默认转换为MiddleA,也可以默认转换为MiddleB,如果不明确指出就会出现歧义。这时可以改为:
Function(static_cast(bottom));Function(static_cast(bottom));
程序可以运行了。但是如果不小心这样使用了:

Top top;
Function(static_casttop);

  这样编译可以通过,但是在运行时可能崩溃,因为top不是“一种”MiddleB,但是static_cast不能发现这个问题,这时如果用implicit_cast就不会有这个问题了,在编译时就会给出错误信息。static_cast不进行真正的类型检查(在down_cast和up_cast的时候)。implicit_cast只能用在up_cast,当需要down_cast(这种形式)时候我们就应该使用上面的down_cast(上面的代码)。
down_cast在debug模式下内部使用了dynamic_cast进行验证,在release下使用static_cast替换dynamic_cast。

为什么使用down_cast而不直接使用dynamic_cast?

1.因为但凡程序设计正确,dynamic_cast就可以用static_cast来替换,而后者比前者更有效率。
2.dynamic_cast可能失败(在运行时crash),运行时RTTI不是好的设计,不应该在运行时RTTI或者需要RTTI时一般都有更好的选择。
知乎上有个讨论 为什么说不要使用 dynamic_cast,需要运行时确定类型信息,说明设计有缺陷? - 知乎

总结

  在程序设计中,主要是我们自己代码编写者要明确的知道当前是down_cast还是up_cast,up_cast那就使用implicit_cast,down_cast就用down_cast。

你可能感兴趣的:(c/c++)