的笔记

随时随地编辑

Dynamic、Static、Reinterpret、Const Cast

一、向上类型转换


情形一:
C++ code
class A
{
public:
 virtual void fun()
 {
  int a=0;
 }
};

class B :public A
 2{
 3public:
 4    void fun()
 5    {
 6        int b=0;
 7    }

 8}
;
 9
10int _tmain(int argc, _TCHAR* argv[])
11{
12
13    B obj;
14
15    {
16        A* p = (&obj);
17        p->fun();
18    }

19
20    {
21        A* p = static_cast< A* >(&obj);
22        p->fun();
23    }

24
25    {
26        A* p = dynamic_cast< A* >(&obj);
27        p->fun();
28    }

29
30    {
31        A* p = reinterpret_cast< A* >(&obj);
32        p->fun();
33    }

34
35    return 0;
36}

Disassembly
 1    B obj;
 2  lea         ecx,[obj] 
 3  call        B::B (11A1104h) 
 4
 5    {
 6        A* p = (&obj);
 7  lea         eax,[obj] 
 8  mov         dword ptr [p],eax 
 9        p->fun();
10  mov         eax,dword ptr [p] 
11  mov         edx,dword ptr [eax] 
12  mov         esi,esp 
13  mov         ecx,dword ptr [p] 
14  mov         eax,dword ptr [edx] 
15  call        eax  
16  cmp         esi,esp 
17  call        @ILT+365(__RTC_CheckEsp) (11A1172h) 
18    }

19
20    {
21        A* p = static_cast< A* >(&obj);
22  lea         eax,[obj] 
23  mov         dword ptr [p],eax 
24        p->fun();
25  mov         eax,dword ptr [p] 
26  mov         edx,dword ptr [eax] 
27  mov         esi,esp 
28  mov         ecx,dword ptr [p] 
29  mov         eax,dword ptr [edx] 
30  call        eax  
31  cmp         esi,esp 
32  call        @ILT+365(__RTC_CheckEsp) (11A1172h) 
33    }

34
35    {
36        A* p = dynamic_cast< A* >(&obj);
37  lea         eax,[obj] 
38  mov         dword ptr [p],eax 
39        p->fun();
40  mov         eax,dword ptr [p] 
41  mov         edx,dword ptr [eax] 
42  mov         esi,esp 
43  mov         ecx,dword ptr [p] 
44  mov         eax,dword ptr [edx] 
45  call        eax  
46  cmp         esi,esp 
47  call        @ILT+365(__RTC_CheckEsp) (11A1172h) 
48    }

49
50    {
51        A* p = reinterpret_cast< A* >(&obj);
52  lea         eax,[obj] 
53  mov         dword ptr [p],eax 
54        p->fun();
55  mov         eax,dword ptr [p] 
56  mov         edx,dword ptr [eax] 
57  mov         esi,esp 
58  mov         ecx,dword ptr [p] 
59  mov         eax,dword ptr [edx] 
60  call        eax  
61  cmp         esi,esp 
62  call        @ILT+365(__RTC_CheckEsp) (11A1172h) 
63    }

看看B:B()的代码,这个编译器自动帮我们加上去的代码,如果没有虚报是不会有的。
 1B::B:
 2  push        ebp  
 3  mov         ebp,esp 
 4  sub         esp,0CCh 
 5  push        ebx  
 6  push        esi  
 7  push        edi  
 8  push        ecx  
 9  lea         edi,[ebp-0CCh] 
10  mov         ecx,33h 
11  mov         eax,0CCCCCCCCh 
12  rep stos    dword ptr es:[edi] 
13  pop         ecx  
14  mov         dword ptr [ebp-8],ecx 
15  mov         ecx,dword ptr [this
16  call        A::A (1321109h) 
17  mov         eax,dword ptr [this
18  mov         dword ptr [eax],offset B::`vftable' (1325740h) 
19  mov         eax,dword ptr [this
20  pop         edi  
21  pop         esi  
22  pop         ebx  
23  add         esp,0CCh 
24  cmp         ebp,esp 
25  call        @ILT+365(__RTC_CheckEsp) (1321172h) 
26  mov         esp,ebp 
27  pop         ebp  
28  ret              


情形二:

C++ CODE
只是在上文改动一处:去掉A::fun()的声明virtual。

Disassembly对比
                  左:无virtual声明                                                           右:有virtual声明

结论: 无论哪种cast,向上类型都一样。函数调用只与虚表有关。向上类型转换是最常见的一种转换,常见的大部分代码都是用"向上类型转换+虚函数"这种黄金组合完成一些c++类库,例如MFC,QT,OGRE.这种转换很符合常规,基本不会出错。

二、向下类型转换

情形一:

C++ CODE

A和B的声明同上,只是改变A::fun()是虚函数。
 1    A obj;
 2
 3    {
 4        //B* p = (&obj);
 5        //p->fun();
 6        //error C2440: 'initializing' : cannot convert from 'A *' to 'B *'
 7        //Cast from base to derived requires dynamic_cast or static_cast
 8    }

 9
10    {
11        B* p = static_cast< B* >(&obj);
12        p->fun();
13    }

14
15    {
16        B* p = dynamic_cast< B* >(&obj);
17        p->fun();
18    }

19
20    {
21        B* p = reinterpret_cast< B* >(&obj);
22        p->fun();
23    }

Disassembly
 1    A obj;
 2  lea         ecx,[obj] 
 3  call        A::A (9310FFh) 
 4
 5    {
 6        //B* p = (&obj);
 7        //p->fun();
 8        //error C2440: 'initializing' : cannot convert from 'A *' to 'B *'
 9        //Cast from base to derived requires dynamic_cast or static_cast
10    }

11
12    {
13        B* p = static_cast< B* >(&obj);
14  lea         eax,[obj] 
15  mov         dword ptr [p],eax 
16        p->fun();
17  mov         eax,dword ptr [p] 
18  mov         edx,dword ptr [eax] 
19  mov         esi,esp 
20  mov         ecx,dword ptr [p] 
21  mov         eax,dword ptr [edx] 
22  call        eax  
23  cmp         esi,esp 
24  call        @ILT+355(__RTC_CheckEsp) (931168h) 
25    }

26
27    {
28        B* p = dynamic_cast< B* >(&obj);
29  push        0    
30  push        offset B `RTTI Type Descriptor' (937014h) 
31  push        offset A `RTTI Type Descriptor' (937000h) 
32  push        0    
33  lea         eax,[obj] 
34  push        eax  
35  call        @ILT+450(___RTDynamicCast) (9311C7h) 
36  add         esp,14h 
37  mov         dword ptr [p],eax 
38        p->fun();
39  mov         eax,dword ptr [p] 
40  mov         edx,dword ptr [eax] 
41  mov         esi,esp 
42  mov         ecx,dword ptr [p] 
43  mov         eax,dword ptr [edx] 
44  call        eax  
45  cmp         esi,esp 
46  call        @ILT+355(__RTC_CheckEsp) (931168h) 
47    }

48
49    {
50        B* p = reinterpret_cast< B* >(&obj);
51  lea         eax,[obj] 
52  mov         dword ptr [p],eax 
53        p->fun();
54  mov         eax,dword ptr [p] 
55  mov         edx,dword ptr [eax] 
56  mov         esi,esp 
57  mov         ecx,dword ptr [p] 
58  mov         eax,dword ptr [edx] 
59  call        eax  
60  cmp         esi,esp 
61  call        @ILT+355(__RTC_CheckEsp) (931168h) 
62    }

情形二:
C++ CODE
A和B的声明同上,只是改变A::fun()不是虚函数。
    A obj;

    
{
        
//B* p = (&obj);
        
//p->fun();
        
//error C2440: 'initializing' : cannot convert from 'A *' to 'B *'
        
//Cast from base to derived requires dynamic_cast or static_cast
    }


    
{
        B
* p = static_cast< B* >(&obj);
        p
->fun();
    }


    
{
        
//B* p = dynamic_cast< B* >(&obj);
        
//p->fun();
        
//error C2683: 'dynamic_cast' : 'A' is not a polymorphic type
        
//*    1>        */e:\develop\test\testr555\testr555.cpp(7) : see declaration of 'A'
    }


    
{
        B
* p = reinterpret_cast< B* >(&obj);
        p
->fun();
    }


Disassembly
    A obj;

    
{
        
//B* p = (&obj);
        
//p->fun();
        
//error C2440: 'initializing' : cannot convert from 'A *' to 'B *'
        
//Cast from base to derived requires dynamic_cast or static_cast
    }


    
{
        B
* p = static_cast< B* >(&obj);
  lea         eax,[obj] 
  mov         dword ptr [p],eax 
        p
->fun();
  mov         ecx,dword ptr [p] 
  call        B::fun (10C1028h) 
    }


    
{
        
//B* p = dynamic_cast< B* >(&obj);
        
//p->fun();
        
//error C2683: 'dynamic_cast' : 'A' is not a polymorphic type
        
//*    1>        */e:\develop\test\testr555\testr555.cpp(7) : see declaration of 'A'
    }


    
{
        B
* p = reinterpret_cast< B* >(&obj);
  lea         eax,[obj] 
  mov         dword ptr [p],eax 
        p
->fun();
  mov         ecx,dword ptr [p] 
  call    

总结:
向下类型转换时,强制类型转换都是不行的。你不能作为一个父亲,却想借着儿子的名号玩一把年轻,用儿子的名义的名号去招摇撞骗以为自己是官二代。不过如果你是儿子,你可以将你的名字换成父亲的,去做在父亲名字下可以做的事,例如表明自己是官二代撞死人撞不死人在倒回来继续撞。

当类型没有虚表的时候,你不能进行向下类型的dynamic_cast,这个时候编译器会报错:
//error C2683: 'dynamic_cast' : 'A' is not a polymorphic type.
不过奇怪的是向上类型转换的时候却没这个错。如果有虚表,还是可以转换的。不过结果是0.也就是说在想下类型转换的时候,'dynamic_cast' 是没有意义的。

三、C++类继承之间转换总结

向上类型转换的时候,你闭着眼睛都可以想出结果,各种转换关键字的反汇编其实都是一样的,都是一个直接赋值。写代码的时候写不写无所谓。
向下类型转换的时候,你得注意了。为了效率,你就酌情选择动态还是静态转换吧。一般情况静态就可以了。
没事不要瞎折腾啊,语言转换不好文档化时分析代码逻辑,也容易出错。

posted on 2011-06-23 11:49 的笔记 阅读(437) 评论(0)  编辑 收藏 引用 所属分类: C++


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理