C++ 类型转换

来源:互联网 发布:国际淘宝怎么开 编辑:程序博客网 时间:2024/06/05 00:31

      • 隐式类型转换
        • 1 数值类型转换
        • 2 指针类型转换
      • 显式类型转换
        • 1 explicit关键字
        • 1 强制类型转换
          • 11 static_cast
          • 12 dynamic_cast
          • 13 const_cast
          • 14 reinterpret_cast
      • 参考资料

C++类型转换大体上包括隐式类型转换和显式类型转换。

1. 隐式类型转换

隐式类型转换是自动执行的,无需显式的操作符。 隐式类型转换发生在很多地方,比如函数实参到形参的类型转换、函数返回值类型的自动转换等等。

1.1 数值类型转换

从小整数类型(char、short)转换到int,或者从float转换到double,这种“提升型”的转换通常不会造成数值差异。但是下面的一些情形可能存在一些转换误差,使得编译器产生警告。

  • 负数转化为无符号类型,通常会采用二进制补码表示。 (编译器不警告有符号和无符号整数类型之间的隐式转换)
    int a = -1;    unsigned int  b = a;   // b = 2^32 - 1 = 4294967295
  • 无论是转换到bool类型或者是有bool类型进行转换: false等价于0(数值类型)或者空指针(指针类型); true则等价于其它任何数值或者由true转化为1。
    int a = -2;     bool b = a; //则b = true
  • 浮点数转化为整数会采取截断操作,即移除小数部分。如果转换时发生了数值溢出,可能出现未定义的行为。
    float a = -1.5f;    int   b = a; // b = -1

1.2 指针类型转换

指针通常存在以下转换:

  • 空指针可以转换到任意指针类型;
  • 任意指针类型都可以转换到void* 指针;
  • 继承类指针可以转换到可访问的明确的基类指针, 同时不改变const或者volatile属性;
  • 一个C风格的数组隐式把数组的第一个元素转换为一个指针。 虽然此方法很方便,但它也有潜在的错误。 例如,下面的设计不良的代码示例看似荒谬,但它会在Visual C++的编译并生成的结果’p’。 首先,“Help”字符串常量转换为一个指向数组的第一个元素 char*类型指针,该指针向后移动3个元素后,指向最后一个元素’P’。
char* s = "Help" + 3;  

2. 显式类型转换

旧有的C风格的强制类型转换是不推荐的:

(int) x; // old-style cast, old-style syntax  int(x); // old-style cast, functional syntax  

因为在代码中不显眼,容易被忽略, 而且旧式强制转换实际上是困难且容易出错的。

2.1 explicit关键字

C++提供了关键字explicit,可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生。即声明为explicit的构造函数不能在隐式转换中使用。

先看一下隐式转换的情形:

// 类的通过构造函数的隐式转换:#include <iostream>using namespace std;class A {};class B {public:  // conversion from A (constructor):  B (const A& x) {}  // conversion from A (assignment):  B& operator= (const A& x) {return *this;}  // conversion to A (type-cast operator)  operator A() {return A();}};int main (){  A foo;  B bar = foo;    // 调用构造函数实现隐式类型转换  bar = foo;      // calls assignment  foo = bar;      // calls type-cast operator,相当于 foo = A(bar);  return 0;}

再看下面的一个例子:

#include <iostream>using namespace std;class A {};class B {public:  explicit B (const A& x) {}  B& operator= (const A& x) {return *this;}  operator A() {return A();}};void fn (B x) {}  // 当我们希望x只能是B类型时,我们就需要禁止隐式类型转换int main (){  A foo;  B bar (foo);  // 必须显式类型转换,不再允许B bar = foo;   bar = foo;  foo = bar;//  fn (foo);  // 不允许隐式类型转换  fn (bar);    return 0;}

2.1 强制类型转换

C++ 提供四种转换操作符来实现显式类型转换:

2.1.1 static_cast
static_cast <new_type> (expression)

static_cast强制转换只会在编译时检查,但没有运行时类型检查来保证转换的安全性。同时,static_cast也不能去掉expression的const、volitale、或者__unaligned属性。

其主要应用场景有:

  • 用于类层次结构中基类和子类之间指针或引用的转换。进行上行转换(把子类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成子类指针或引用)时,由于没有动态类型检查,所以是不安全的。
  • 用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
  • 把void指针转换成目标类型的指针(不安全!!)
  • 把任何类型的表达式转换成void类型
  • 将enum class值转化为整数或者浮点数
  • 转换为右值引用
2.1.2 dynamic_cast
dynamic_cast <new_type> (expression)

new_type 必须是一个指针或引用或“指向 void 的指针”。 如果 new_type 是指针,则expression 的类型必须是指针,如果 type-id 是引用,则expression为左值。 如果转型失败会返回null(转型对象为指针时)或抛出异常(转型对象为引用时)。dynamic_cast 会动用运行时信息(RTTI)来进行类型安全检查,因此dynamic_cast 存在一定的效率损失。

dynamic_cast 的一个重要作用就是要确保转换结果应该指向一个完整的目标类型。 下面给一个示例:

#include <iostream>#include <exception>using namespace std;class Base { virtual void dummy() {} };class Derived: public Base { int a; };int main () {  try {    Base * pba = new Derived;    Base * pbb = new Base;    Derived * pd;    pd = dynamic_cast<Derived*>(pba);    if (pd==0) cout << "Null pointer on first type-cast.\n";    pd = dynamic_cast<Derived*>(pbb);    if (pd==0) cout << "Null pointer on second type-cast.\n";  } catch (exception& e) {cout << "Exception: " << e.what();}  return 0;}

输出结果为:

Null pointer on second type-cast.

分析: 尽管pba和pbb都是Base指针类型,但其指向的对象却分别是Derived 和 Base。而由于Base相比Derived少了int a的定义,因此无法完整的由Base转到Derived。

此外,dynamic_cast只有在基类存在虚函数(虚函数表)的情况下才有可能将基类指针转化为子类。

2.1.3 const_cast
const_cast <new_type> (expression)

new_type 必须是一个指针、引用或者指向对象类型成员的指针。

const_cast用于去除除对象的const或者volatile属性。

void Func(double& d) { ... }  void ConstCast()  {     const double pi = 3.14;     Func(const_cast<double&>(pi)); //No error.  }
2.1.4 reinterpret_cast
reinterpret_cast <new_type> (expression)

new_type必须是一个指针、引用、算术类型、函数指针或者成员指针。其转换结果与编译平台息息相关,不具有可移植性,因此在一般的代码中不常见到它。reinterpret_cast 常用的一个用途是转换函数指针类型,即可以将一种类型的函数指针转换为另一种类型的函数指针,但这种转换可能会导致不正确的结果。总之,reinterpret_cast只用于底层代码,一般我们都用不到它,如果你的代码中使用到这种转型,务必明白自己在干什么

参考资料

  • cplusplus type conversiones http://www.cplusplus.com/doc/tutorial/typecasting/
  • 【C++专题】static_cast, dynamic_cast, const_cast探讨 http://www.cnblogs.com/chio/archive/2007/07/18/822389.html
  • 类型转换与类型安全https://msdn.microsoft.com/zh-cn/library/hh279667.aspx
原创粉丝点击