C++实现之——转型

C++中的转型语法有三种形式:

1)C风格的转换:

T(expression)
(T)expression

上面两种形式都是将expression转换为T类型。

2)C++新型转换:
a. const_cast<T>(expression)

   将对象的常量性转除,是唯一有此能力的C++风格转型操作符; 

b. dynamic_cast<T>(expression)

   主要用来执行“安全向下转型”,也就是觉得对象是否归属继承体系中的某个类型。它是唯一无法由旧式语法执行的动作,也是唯一可能耗费重大运行成本的转型动作。

c. reinterpret_cast<T>(expression)

  意图执行低级转型,实际动作可能取决于编译器,因此不可移植。如将一个pointer to int 转为int。这一类转型在低级代码意外很少见。

d. static_cast<T>(expression)

  用来强迫隐式转换,如将non-const转换为const对象,将int类型转为double类型。 

使用中,旧式类型及(1)中的方式仍然是合法的,但新的C++转换类型更受欢迎,因为它很容易在代码中被人工或者工具辨识,而且,它方便编译器捕捉错误。

在C++中,转型并不是什么都没做,任何一个类型转换往往真的令编译器编译出运行期间执行的代码,例如将int转换为double时,由于在大部分计算器体系结构中,int的底层表述不同于double的底层表述,所以这一转换几乎肯定会产生一些代码。

另外,如果你要对自己进行转型操作时,请格外注意,例如下面的代码:

 1 class Window
 2 {
 3 public:
 4       virtual void onResize() { ... }
 5       ...
 6 };
 7 
 8 class SpecialWindow :public Window 
 9 {
10 public:
11      virtual void onResize()
12      {
13           static_cast<Window>(*this).onResize();
14           ...
15      }
16      ...
17 };

上面的代码中的本意是在派生类的onResize成员函数中先调用基类的onResize函数,为了调用基类的函数,程序中将派生类转换为Window,然后调用Window的onResize函数,然后实现自己的具体行为。但真的实现却是这样的,它首先产生一个当前对象的base class成分的一个副本,然后调用副本的成员函数onResize,而不是真正在本对象上的base class成分中调用基类函数,因此如果base class的成员函数中有对属性的修改操作,假设SpecialWindow的成员函数onResize也对属性有修改操作,那么其对象执行onResize后,base class的成分是没有被修改的,而派生来的成分则是修改了的,这显然是不合理的。为了解决这个问题,应拿掉类型转换,执行如下:

1 void onReize()
2 {
3      Window::onResize();  //调用Window::onResize()作用于*this身上
4      ...
5 }

通常情况下,dynamic_cast的许多实现版本运行速度非常慢,例如在深度继承和多重继承体系中,一个对象的转换可能涉及到许多个对象的转换,因此要格外注意。在非常注重效率的程序中,要对dynamic_cast保持高度敏感和猜疑。它的通常的一个用法是将base class的pointer或者reference转换为derived class的pointer或reference,但通常情况下,这可以被其他方法所替代,如通过virtual函数。

总之,优良的C++代码需要应尽量避免转型操作,如果实在需要,也最好将它隔离在函数中,这样函数的调用者就不会受函数内部的行为的影响。 

以上整理自Effective C++ 中文版第三版case 27. 

posted on 2013-06-03 15:40  Sophia-呵呵小猪  阅读(205)  评论(0编辑  收藏  举报