一、向上类型转换
情形一:
C++ code
Disassembly
1
B obj;
2
lea ecx,[obj]
3
call B::B (11A1104h)
4![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
5![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
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![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
20![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
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![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
35![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
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![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
50![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
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()的代码,这个编译器自动帮我们加上去的代码,如果没有虚报是不会有的。
1
B::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声明
![](http://www.cppblog.com/images/cppblog_com/flyindark/virtual对比图.gif)
结论: 无论哪种cast,向上类型都一样。函数调用只与虚表有关。向上类型转换是最常见的一种转换,常见的大部分代码都是用"向上类型转换+虚函数"这种黄金组合完成一些c++类库,例如MFC,QT,OGRE.这种转换很符合常规,基本不会出错。
二、向下类型转换
情形一:
C++ CODE
A和B的声明同上,只是改变A::fun()是虚函数。
1
A obj;
2![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
3![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
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![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
10![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
11
B* p = static_cast< B* >(&obj);
12
p->fun();
13
}
14![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
15![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
16
B* p = dynamic_cast< B* >(&obj);
17
p->fun();
18
}
19![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
20![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
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![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
5![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
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![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
12![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
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![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
27![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
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![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
49![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
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;
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
//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
}
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
B* p = static_cast< B* >(&obj);
p->fun();
}
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
//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'
}
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
B* p = reinterpret_cast< B* >(&obj);
p->fun();
}
Disassembly
A obj;
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
//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
}
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
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)
}
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
//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'
}
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
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++类继承之间转换总结
向上类型转换的时候,你闭着眼睛都可以想出结果,各种转换关键字的反汇编其实都是一样的,都是一个直接赋值。写代码的时候写不写无所谓。
向下类型转换的时候,你得注意了。为了效率,你就酌情选择动态还是静态转换吧。一般情况静态就可以了。
没事不要瞎折腾啊,语言转换不好文档化时分析代码逻辑,也容易出错。