如有疑问,请分析并检查组件 :)
这是三种情况的比较(dynamic_cast、虚拟函数 (type) 和 enum)。为简单起见,special 方法在所有情况下都是相同的,仅在实际情况下才能看到差异。然而,在现实世界中,“特别”每次都会有所不同,否则就没有意义了。
by_enum 还提供了在开始时 vcall 中发生的情况的演示。
enum Type { D1_t, D2_t, D3_t, D4_t, D5_t };
struct Base
{
virtual ~Base() = default;
virtual Type type() = 0;
};
struct D1 : public Base
{
Type type() override { return D1_t; }
int special1();
};
struct D2 : public Base{
Type type() override { return D2_t; }
int special2();
};
struct D3 : public D2{
Type type() override { return D3_t; }
int special3();
};
struct D4 : public D2{
Type type() override { return D4_t; }
int special4();
};
struct D5 : public D4{
Type type() override { return D5_t; }
int special5();
};
int by_dynamic(Base* b)
{
if(auto d = dynamic_cast<D1*>(b)) return d->special1();
else if(auto d = dynamic_cast<D2*>(b)) return d->special2();
else if(auto d = dynamic_cast<D3*>(b)) return d->special3();
else if(auto d = dynamic_cast<D4*>(b)) return d->special4();
else if(auto d = dynamic_cast<D5*>(b)) return d->special5();
}
int by_enum(Base* b)
{
switch(b->type())
{
case D1_t:
return static_cast<D1*>(b)->special1();
break;
case D2_t:
return static_cast<D2*>(b)->special2();
break;
case D3_t:
return static_cast<D3*>(b)->special3();
break;
case D4_t:
return static_cast<D4*>(b)->special4();
break;
case D5_t:
return static_cast<D5*>(b)->special5();
break;
}
}
这是by_dynamic(GCC-5.2、-O3)的相关 ASM。所以我认为,如果你受到性能限制,那就去枚举吧。
by_dynamic(Base*):
testq %rdi, %rdi
je .L15
pushq %rbx
xorl %ecx, %ecx
movl typeinfo for D1, %edx
movl typeinfo for Base, %esi
movq %rdi, %rbx
call __dynamic_cast
testq %rax, %rax
je .L3
popq %rbx
movq %rax, %rdi
jmp D1::special1()
.L3:
xorl %ecx, %ecx
movl typeinfo for D2, %edx
movl typeinfo for Base, %esi
movq %rbx, %rdi
call __dynamic_cast
testq %rax, %rax
je .L4
popq %rbx
movq %rax, %rdi
jmp D2::special2()
.L4:
xorl %ecx, %ecx
movl typeinfo for D3, %edx
movl typeinfo for Base, %esi
movq %rbx, %rdi
call __dynamic_cast
testq %rax, %rax
je .L5
popq %rbx
movq %rax, %rdi
jmp D3::special3()
.L5:
xorl %ecx, %ecx
movl typeinfo for D4, %edx
movl typeinfo for Base, %esi
movq %rbx, %rdi
call __dynamic_cast
testq %rax, %rax
je .L6
popq %rbx
movq %rax, %rdi
jmp D4::special4()
.L6:
xorl %ecx, %ecx
movl typeinfo for D5, %edx
movl typeinfo for Base, %esi
movq %rbx, %rdi
call __dynamic_cast
testq %rax, %rax
je .L2
popq %rbx
movq %rax, %rdi
jmp D5::special5()
.L2:
popq %rbx
.L15:
ret
对于by_enum
by_enum(Base*):
pushq %rbx
movq (%rdi), %rax
movq %rdi, %rbx
call *16(%rax)
cmpl $4, %eax
ja .L18
movl %eax, %eax
movq %rbx, %rdi
jmp *.L20(,%rax,8)
.L20:
.quad .L19
.quad .L21
.quad .L22
.quad .L23
.quad .L24
popq %rbx
jmp D4::special4()
popq %rbx
jmp D5::special5()
popq %rbx
jmp D1::special1()
popq %rbx
jmp D2::special2()
popq %rbx
jmp D3::special3()
.L18:
popq %rbx
ret