如何使用GCC扩展来判断重载方法是否被覆盖

问题描述 投票:0回答:1

这里解释了 gcc 提供了一个扩展,它接受一个指向对象的指针和一个指向虚拟方法的指针,并解决了动态分派的问题,给出了一个自由函数指针。我不清楚当虚拟函数重载时如何最好地做到这一点。我下面有一些示例代码。

科利鲁

#include <memory> #include<iostream> using namespace std; struct B{ virtual void f(){cout<<"b\n";} virtual void f() const {}//this makes things more interesting, can no longer use (F)&B::f, would need extra cast (F)(PTM)&B::f bool overridesf(){ constexpr void (B::*ptm)()=&B::f; using PTM = decltype(ptm); using F = void (*)(B*); auto thisF = (F)(this->*ptm); auto notBaseF = (F)(PTM)&B::f; auto baseF = (F)(B().*ptm);//can simply use (F)&B::f when no overload is present B b; //below, all print b when `this` is a B thisF(this);//c when `this` is a C thisF(&b);//c when `this` is a C baseF(this);//b when `this` is a C baseF(&b);//b when `this` is a C notBaseF(this);//c when `this` is a C notBaseF(&b);//c when `this` is a C //return thisF!=notBaseF; //wrong: is false when this is a c return thisF!=baseF; //works correctly: true when this is a c } }; struct C:B{ void f()override{cout<<"c\n";} }; int main() { auto b=make_unique<B>(); cout<<b->overridesf()<<endl; b=make_unique<C>(); cout<<b->overridesf(); }

我有兴趣查看一个对象是否覆盖了第一个非常量 
f

,并且我创建了一个函数

overridesf
来执行此操作。这个想法是在
this
上进行动态调度以获取函数指针 (
thisF
) 并将此函数指针与我们对已知不会覆盖 f 的对象进行动态调度时得到的结果进行比较 (
baseF
).
事实上,如果

f

没有被重载,那么我们可以简单地通过表达式

baseF
得到
(F)&B::f
函数指针。然而,如果
f
被重载,这个表达式就会变得不明确,我们将不得不执行
(F)(PTM)&B::f
,其中 PTM 强制转换解决了重载的歧义。但是(我认为)表达式
(F)(PTM)&B::f
不是 PMF 常量的直接转换(因为中间转换),因此链接页面末尾有关直接转换的部分不适用,您需要一个对象(在我的例子中
B()
)。
我有两个问题。首先有没有更好的方法来获得

baseF

?如果接口有许多纯虚函数,那么创建一个派生类来重写所有纯虚函数(但当然不是

f
)以构造一个对象以获得
baseF
会很烦人。
另一个问题是 

notBaseF

是怎么回事,它是由表达式

(F)(PTM)&B::f
定义的。据推测这是未定义的行为,但是有没有解释为什么
notBaseF(&b)
的行为是由
this
的动态类型决定的?
    

c++ gcc overloading virtual-functions pointer-to-member
1个回答
0
投票
回顾

好的,据我了解,您希望节省访问 vtable(“动态调度”)的时间 - 以防函数未被覆盖。为了做到这一点,您将应用像

overridesf

中那样的动态方法 - 这将需要更多时间。

回答

没有任何方法(判断函数是否被覆盖)比 vtable 访问更快。我没有证据,但原因如下。如果这是正确的,那么这样的优化是不可能的。

为什么?

vtable 访问需要访问一个以上的间接地址 - 可能只是一个 CPU 周期。判断函数是否被覆盖的动态方法至少需要访问两个地址和一个比较。

一条出路

首先确定动态调度需要多少时间以及函数本身需要多少时间(净时间)以及优化是否值得。如果开销只有 10%,那么如果找到静态访问方法,您将获得 10% 的收益。

静态调度

如果静态调度的优化确实值得,那么不要使用动态方法,而应使用静态方法。利用调用者的知识,他们可能知道必须调用哪个函数。模板可以帮助实现这一目标。

© www.soinside.com 2019 - 2024. All rights reserved.