C++风格的转型运算符小结
为了改正C中丑陋的转型操作,C++中引入了四个新的转型操作符,分别是:
dynamic_cast
const_cast
static_cast
reinterpret_cast
1.dynamic_cast
这个转型操作符主要用在安全的向下转型(safe downcasting)中,也就是从基类指针/引用向派生类指针/引用的转型。例如:
Code: [View More of this Code] [View Even More of this Code] [View Less of this Code] [Select All of this Code]
class A {...};
class B:public A {...};
A* a = new B;
B* b;
b = dynamic_cast<B *> a;
当你将dynamic_cast用在指针上时,如果成功,就传回一个转型目标的指针,如果失败,则传回null指针。所以用到dynamic_cast的
时候必然会导致if-then-else的程序风格,其中else就是用来检测转型失败的情况([1]第39条)。例子如下:
Code: [View More of this Code] [View Even More of this Code] [View Less of this Code] [Select All of this Code]
#include <iostream>
using namespace std;
class A {
public:
virtual void do_sth(){
cout<<"aaa\n";
}
};
class B : public A {
public:
virtual void do_sth(){
cout<<"bbb\n";
}
};
class C : public A {
public:
virtual void do_sth(){
cout<<"ccc\n";
}
};
int main(){
A* a1 = new B;
A* a2 = new C;
B* b;
if(b = dynamic_cast<B *>(a1))//转换成功
b->do_sth();
else
cout<<"error\n";
if(b = dynamic_cast<B *>(a2))//转换失败
b->do_sth();
else
cout<<"error\n";
}
2.const_cast
此转型操作符用来将对象或指针的常量性(sonstness)转型掉。例如:
const A * a1;
A * a2 = const_cast<A *> (a1);
需要注意的是,const_cast转型并不总是成功的,当遇到转型的对象本身就是const的时候,那么将其常量性转型,结果未定义。看一下下面的例子:
Code: [View More of this Code] [View Even More of this Code] [View Less of this Code] [Select All of this Code]
// constcast.cpp from [2]
#include <iostream>
using std::cout;
void change(const int * pt, int n);
int main()
{
int pop1 = 38383;
const int pop2 = 2000;
cout << "pop1, pop2: " << pop1 << ", " << pop2 << '\n';
change(&pop1, -1);
change(&pop2, -1);
cout << "pop1, pop2: " << pop1 << ", " << pop2 << '\n';
return 0;
}
void change(const int * pt, int n)
{
int * pc;
if (n < 0)
{
pc = const_cast<int *>(pt);
*pc = 100;
}
}
输出的结果是:
pop1, pop2: 38383, 2000
pop1, pop2: 100, 2000
可见,pop2的值并没有改变(有些编译器会产生一个pop2的临时变量,并将其地址值赋给pc。在C++标准中,这种情况下的行为是不确定的[2])。
3.static_cast
此转型操作符用于内建数据类型之间的转型。它与C的转型操作最接近。当没有其他适当的转型操作符可用时,就使用它。它可以将整型转换为枚举型,双精度型转换为整型,浮点型转换为长整型等等。例如:
Code: [View More of this Code] [View Even More of this Code] [View Less of this Code] [Select All of this Code]
int n=9;
double d = static_cast < double > (n);
上面的例子中,我们将一个变量从 int 转换到 double. 这些类型的二进制表达式是不同的。要将整数 9 转换到 双精度整数 9,static_cast需要正确地为双精度整数 d 补足比特位。其结果为 9.0 。
4.reinterpret_cast
此转型操作符的结果取决于编译器,用于修改操作数类型,非类型安全的转换符。举例如下:
Code: [View More of this Code] [View Even More of this Code] [View Less of this Code] [Select All of this Code]
int main() { // from [2]
struct dat { short a; short b;};
long value = 0xA224B118;
dat * pd = reinterpret_cast<dat *> (&value);
cout << pd->a; // display first 2 bytes of value
return 0;
}
该例中将long型转换成struct,但此代码是不可移植的,在IBM兼容机和Mac机上的运行结果完全不一样,因为他们存储字节的方式不一样。
reinterpret_cast的使用要非常的谨慎,例如将3中的例子改写如下:
Code: [View More of this Code] [View Even More of this Code] [View Less of this Code] [Select All of this Code]
int n=9;
double d = reinterpret_cast<double & > (n);
这次,与3的结果有所不同。在进行计算以后,d 包含无用值。这是因为 reinterpret_cast 仅仅是复制 n 的比特位到 d,没有进行必要的分析。
以上是我在学习这些转型操作符一个小结,如有不对之处,请各位不啬赐教。
大家有兴趣,可以去这里做一下有关这些转型操作符的练习。
注:以上例子在 VC6 + Intel C++ Compiler 8.0 下编译运行通过(别忘了打开RTTI,加参数/GR)。
参考文献:
[1] Effective C++ 中文版 Scott Meyers 侯捷译
[2] C++ Primer Plus, 4th Edition, Stephen Prata
[3] STATIC_CAST VERSUS REINTERPRET_CAST(Topica转载)
2005年1月22日 9:23