这种人工剥夺机会的做法合法/可行吗

Is this manual devirtualization legal / viable?

本文关键字:机会      更新时间:2023-10-16

对于我的一个项目,我终于需要使用我的第一个多态类(std::cout除外(。

我正在研究如何确保我有100%的电话——至少在某些情况下是这样。

这个守则合法可行吗?

dynamic_cast会有多慢?如果我在构造函数中支付一次,那么我将始终能够直接使用类B,所以这听起来是一个好的练习?

在那之后,C风格的转换会很快吗?还是我必须存储指向B的指针?

struct A{
virtual void x();
};
struct B : A{
void x() override;
};
struct X{
A *a;
bool fB;
X(A &a) : a(&a), fB( dynamic_cast<B *>(&a) ){}
void f(){
if (fB){
((B*)a)->x();
}else{
a->x();
}
}
};

void fn(A &a){
X x(a);
x.f();
}

int main(){
B b;
X x(b);
x.f();
}

对于您现有的代码,我实际上希望您的编译器优化掉if语句和您的强制转换,因为这会使代码变得不那么简单。

从编译器的角度来看,您的代码库可能如下所示:

struct A{
virtual void x();
};
struct B : A{
void x() override;
};
struct C : B{
void x() override;
};

因此,当is看到您的强制类型和函数调用:static_cast<B*>(a)->x()时,它仍然必须访问与调用a->x()时相同的虚拟表,因为可能存在潜在的类C。(请注意,我使用static_cast,因为c样式转换是错误的来源(

如果您想直接调用B,最好将方法或类设为final。另一个好的方法是使用概要文件引导的优化,在这种情况下,他们经常比较vtable指针。

回答你的附带问题?

  • 代码合法吗?是的,是的
  • 这可行吗?是的,考虑到上面的评论
  • dynamic_cast的速度有多慢?慢慢来,我会争辩为这写一个好的基准,然而,我不知道如何做到这一点,并使其变得现实
  • 这种做法好吗?不,这会降低多态性的可用性
  • static_cast会很快吗?是的,它很快,在这种特殊情况下,不需要任何说明。与bool相比,在复杂继承的特定情况下,存储指向B的指针都可以改进。如果它需要额外的内存,也可能导致性能下降。只要在可执行文件中有额外的程序集,就可以实现另一个减少

我的建议,尤其是因为你是C++的新手:不要这样做或任何其他手动优化。编译器可以为您做很多工作。每次手动优化之后都会导致额外的维护,只有当您确实有性能问题时,才可以使用这些技巧。

哦,如果你想知道实际的汇编代码是什么,你可以在编译器资源管理器上进行实验

您尝试更改对分支的虚拟调用。

我已经不确定它是否更快了,

但更糟糕的是,您不能删除虚拟调用,因为B可以有子子通道,您至少必须使void B::x() final允许编译器取消调用的机会。

若编译器可以像main中那样访问具体类型(和代码(,它可能能够单独取消调用的机会。