C风格的强制转换在C++依然能用,但是C++鼓励程序员采用新风格的强制转换,即四种cast。const_cast主要用于处理const修饰,和其他几种有很大区别,因此不容易混淆。因此主要记录另外三种cast,不准确,但是便于记忆。

1. static_cast

        普通的强制转换,基类<-->派生类,int <--> double等等。遵循C的隐式转换规则。

2. reinterpret_cast

         最为接近C风格的强制转换,在static_cast基础上支持更宽松类型转换,比如可以把指针类型转换为int类型。

3. dynamic_cast

        最为严格的强制转换,只能进行指针或者引用类型转换,而且要求满足转换安全。即只允许派生类类型向基类类型转换,否则抛出异常。

        结合类的派生,考察以下程序

 
  
  1.  
  2. #include <iostream>  
  3.  
  4. using namespace std;  
  5.  
  6. class base  
  7. {  
  8. public:  
  9.     base(){cout << "Construct Base\n";}  
  10.      virtual void print(){cout << "Base\n";}  
  11. };  
  12.  
  13. class derive : public base  
  14. {  
  15. public:  
  16.     derive(){cout << "Construct Derive\n";}  
  17.      void print(){cout <<"derive\n"; }  
  18. };  
  19.  
  20. int main()  
  21. {  
  22.     derive dl;  
  23.     (static_cast<base> (dl)).print(); // "Base"  
  24.     (static_cast<base&> (dl)).print(); // "derive"  
  25.     derive * dp = new derive;  
  26.     //cout << (static_cast<int> (dp));   // 无法从“derive *”转换为“int”  
  27.     cout <<(reinterpret_cast<int>(dp)) << endl;  
  28.     (reinterpret_cast<base*> (dp))->print();  
  29.     delete dp;  
  30.  
  31.     while(1);  
  32.     return 0;  

        不难看出, static_cast是不能把指针类型转为整型,但是reinterpret_cast可以。我们可以理解为,reinterpret_cast是进行的内存级别的转换。

        但是,其中有个蹊跷的地方,为什么static_cast做普通类型转换,调用的是基类的函数,难道是不查询虚表了吗?于是,我们进行下面的尝试:

 
  
  1. #include <iostream>  
  2. using namespace std;  
  3.  
  4. class base  
  5. {  
  6. public:  
  7.     base(){cout << "Construct Base\n";}  
  8.      virtual void print(){cout << "Base\n";}  
  9. };  
  10.  
  11. class derive : public base  
  12. {  
  13. public:  
  14.     derive(){cout << "Construct Derive\n";}  
  15.      void print(){cout <<"derive\n"; }  
  16. };  
  17.  
  18. int main()  
  19. {  
  20.     derive dl;  
  21.     cout << (reinterpret_cast <int> (&dl)) << endl;  
  22.     cout << reinterpret_cast <int> (& static_cast<base>(dl)) << endl;  
  23.     cout << reinterpret_cast <int> (& static_cast<base&> (dl)) << endl;  
  24.     while(1);  
  25.     return 0;  

        执行结果:

 
  
  1. Construct Base  
  2. Construct Derive  
  3. 3079920  
  4. 3079716  
  5. 3079920 

        所以,虚表一样查询了,但是由于不是引用类型的转换,编译器重新生成了基类的实例。因此,查询的是基类的虚表而不是派生类的。

        但是,这里生成的新实例,是按位复制的。那么是因为我们没有定义复制构造函数,还是编译器底层做的复制呢?给两个类添加复制构造函数,继续实验。

 
  
  1. #include <iostream>  
  2. using namespace std;  
  3. class base  
  4. {  
  5. public:  
  6.     base(){cout << "Construct Base\n";}  
  7.     base(const base& b){cout << "Copy construct\n";}  
  8.     virtual void print(){cout << "Base\n";}  
  9. };  
  10.  
  11. class derive : public base  
  12. {  
  13. public:  
  14.     derive(){cout << "Construct Derive\n";}  
  15.     derive(const derive& d){cout << "Derive copy construct";}  
  16.     void print(){cout <<"derive\n"; }  
  17. };  
  18.  
  19. int main()  
  20. {  
  21.     derive dl;  
  22.     cout << (reinterpret_cast <int> (&dl)) << endl;  
  23.     cout << reinterpret_cast <int> (& static_cast<base>(dl)) << endl;  
  24.     cout << reinterpret_cast <int> (& static_cast<base&> (dl)) << endl;  
  25.     while(1);  
  26.     return 0;  

        执行结果:

 
  
  1. Construct Base  
  2. Construct Derive  
  3. 1505236  
  4. Copy construct  
  5. 1505032  
  6. 1505236 

        Bingo! 又让我猜中了,吼吼~因为是基类的对象,调用的只是基类的复制构造函数,把待类型转换的对象复制了一份基类的引用。

        如果使用dynamic_cast就没有这么多问题了,因为只能转换指针和引用类型,不会构造新的对象。