原文翻译自http://www.cplusplus.com/doc/tutorial/typecasting/,觉得这篇文章讲C++类型转换简单明了,所以特别翻译了下。

在C++中,将一个已知的类型转换为另一个类型,我们称呼为类型转换,本文会介绍C++的各种类型转换。

隐式转换

隐式转换不需要任何操作符,它们会自动执行,当值被赋值到兼容类型,就会执行,例如:

short a=2000;
int b;
b=a;

隐式转换,也包括构造函数和运算符的转换,例如:

class A {};
class B { public: B (A a) {} };

A a;
B b=a;

 

显式转换

C++是一个强类型的语言。许多转换,需要显式转换,例如

short a=2000;
int b;
b = (int) a;    // c-like cast notation
b = int (a);    // functional notation

 

上述的类型转换已经满足了基本类型的转换了,但是如果应用于类和指针中,代码可以编译,但是在运行过程中会出错。例如

// class type-casting
#include <iostream>
using namespace std;

class CDummy {
    float i,j;
};

class CAddition {
    int x,y;
  public:
    CAddition (int a, int b) { x=a; y=b; }
    int result() { return x+y;}
};

int main () {
  CDummy d;
  CAddition * padd;
  padd = (CAddition*) &d;
  cout << padd->result();
  return 0;
}

这段代码会在运行期出错,在执行padd->result()时异常退出。

传统明确的类型转换,可以转换成任何其他指针类型任何指针,它们指向的类型无关。在随后的调用成员的结果,会产生一个运行时错误或意外的结果。

 

C++标准转换运算符

传统的类和指针的类型转换,十分不安全,可能会在运行时,由于类型不匹配异常退出,所以C++提供了四个标准转换运算符:dynamic_cast, reinterpret_cast, static_cast, const_cast

dynamic_cast <new_type> (expression)
reinterpret_cast <new_type> (expression)
static_cast <new_type> (expression)
const_cast <new_type> (expression)

 

dynamic_cast

dynamic_cast只能用于指针和引用的对象。其目的是确保类型转换的结果是一个有效的完成所请求的类的对象,所以当我们从一个类转换到这个类的基类,dynamic_cast总是可以成功

class CBase { };
class CDerived: public CBase { };

CBase b; CBase* pb;
CDerived d; CDerived* pd;

pb = dynamic_cast<CBase*>(&d);     // ok: derived-to-base
pd = dynamic_cast<CDerived*>(&b);  // wrong: base-to-derived

当新的类型不是被转换的类型的基类,dynamic_cast无法完成指针的转换,返回NULL,如果dynamic_cast是用来转换为引用类型的转换失败,会抛出”Bad_cast exception”异常。

dynamic_cast 可以转换NULL指针为不相关的类,也可以任何类型的指针为void指针。

dynamic_cast的需要的运行时类型信息(RTTI),保持动态类型跟踪。一些编译器支持此功能默认情况下是禁用的选项。这必须启用运行时类型检查,使用dynamic_cast的正常工作。

 

static_cast

static_cast可以执行相关的类的指针之间的转换,不仅从派生类到基类的转换,也可以做到基类到派生类的转换。static_cast没有在运行时进行安全检查,因此,它是程序员,以确保转换是安全的,但是dynamic_cast的类型安全检查的开销,static_cast是可以避免的。

class CBase {};
class CDerived: public CBase {};
CBase * a = new CBase;
CDerived * b = static_cast<CDerived*>(a);

 

上述代码是合法的,虽然b指向一个不完整的对象,并可能在运行期导致错误。

static_cast也可以用来执行任何其他非指针的转换,例如像基本类型之间的标准转换,也可以是隐式执行

double d=3.14159265;
int i = static_cast<int>(d);

 

reinterpret_cast

reinterpret_cast转换成任何其他指针类型,甚至无关的类,任何指针类型。操作的结果是一个简单的从一个指针到其他的值的二进制拷贝。所有的指针转换是允许的:不管是指针指向的内容还是指针本身的类型。

同时,它也可以把指针转换为整数,但是整数是平台相关的,必须保证整数足够大到可以包含指针本身的内容,最后再转换为一个合法的指针。

class A {};
class B {};
A * a = new A;
B * b = reinterpret_cast<B*>(a)

 

const_cast

const_cast用于操纵对象的常量性,既要设置或删除。例如,一个函数要求一个非const参数,而程序需要传递一个const参数。

#include <iostream>
using namespace std;

void print (char * str)
{
  cout << str << endl;
}

int main () {
  const char * c = "sample text";
  print ( const_cast<char *> (c) );
  return 0;
}

 

typeid

typeid的允许检查表达式的类型
typeid (expression)

 

这个操作符返回一个引用在标准头文件<typeinfo>中定义的常量对象,是一个类型的type_info。这个返回值可以与另一个使用运算符==和!=进行比较两个数据类型或类的名称,或者也可以使用其name() 成员函数获得类型名字(一个0结束的的字符串)。

// typeid
#include <iostream>
#include <typeinfo>
using namespace std;

int main () {
  int * a,b;
  a=0; b=0;
  if (typeid(a) != typeid(b))
  {
    cout << "a and b are of different types:\\n";
    cout << "a is: " << typeid(a).name() << \'\\n\';
    cout << "b is: " << typeid(b).name() << \'\\n\';
  }
  return 0;
}

当typeid应用使用RTTI来跟踪动态对象的类型,那么当typeid的是应用于表达式,其类型是一个多态类,其结果是派生的最完整的对象的类型:

// typeid, polymorphic class
#include <iostream>
#include <typeinfo>
#include <exception>
using namespace std;

class CBase { virtual void f(){} };
class CDerived : public CBase {};

int main () {
  try {
    CBase* a = new CBase;
    CBase* b = new CDerived;
    cout << "a is: " << typeid(a).name() << \'\\n\';
    cout << "b is: " << typeid(b).name() << \'\\n\';
    cout << "*a is: " << typeid(*a).name() << \'\\n\';
    cout << "*b is: " << typeid(*b).name() << \'\\n\';
  } catch (exception& e) { cout << "Exception: " << e.what() << endl; }
  return 0;
}

注意:返回的字符串成员的type_info名称取决于你的编译器和库的具体实现,其典型的类型名称,它不一定是一个简单的字符串.

如果类型typeid的参数是引用操作符(*)开头的指针,而且这个指针是NULL,typeid会抛出一个bad_typeid异常。

 

评论被关闭。