C++风格的转型运算符小结

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

原文地址:https://www.cnblogs.com/huqingyu/p/195728.html