获取指向虚拟方法的指针

Obtain pointer to virtual method?

本文关键字:指针 方法 虚拟 取指 获取      更新时间:2023-10-16

我有一个函数需要在循环中多次调用虚拟方法,并希望有一种方法可以避免每次都产生 vtable 查找的开销。我想也许获得指向该方法的指针会是解决此问题的好方法。下面的代码显示了我正在尝试做的事情,问题是 Derived 中方法的地址无法分配给 Base 成员函数指针。

class Base
{
    public:
    typedef float ( Base::*MFP )( float const & x ) const;
    virtual MFP getMFP( void ) const = 0;
    virtual float function( float const & x ) const = 0;
};
class Derived : public Base
{
    public:
    virtual MFP getMFP( void ) const
    {
        return &Derived::function;
    }
    virtual float function( float const & x ) const
    {
        return x * x;
    }
};
class Other
{
    public:
    float calculate( float const & x, Base * pBase ) const
    {
        Base::MFP function = pBase->getMFP();
        return ( ( *pBase ).*( function ) )( x );
    }
};

有没有办法做我在这里想做的事情?


编辑:

对于仍然感兴趣的人,我对我的代码进行了定时测试。事实证明,动态调度仅将我的计算方法减慢了 0.004%,所以几乎没有。使用 MSVC 2010 进行全面优化编译。

您的想法是基于一个不正确的假设,即创建这样的指针会将 VMT 访问带出循环(即执行一次而不是在循环中重复执行)。

C++通过"指针到成员函数"类型的指针(碰巧绑定到虚拟成员函数)的语言调用总是在调用时解析,而不是在初始化时解析。这意味着即使您创建了这样的指针,它也不会优化任何内容。循环中的每个调用仍将执行对 VMT 的全面访问,就像没有任何指针一样。

在C++中,没有办法在初始化时强制这样的指针指向虚拟函数的特定版本。C++语言根本没有这样的特征。

不要这样做。处理器具有深度管道,并且编译器几乎可以肯定已经缓存了函数指针。你可以通过一些努力来做到这一点。但我保证,在任何不到 10 年的编译器上,这不会有什么区别。

我会避免过早优化,直到它成为一个问题;然后,只有这样,在你分析了你的代码之后,你才会进行更改。 首先要考虑可维护性和可扩展性,如果您仍然遇到性能问题,请进行重构。 在此示例中,查找的开销很小。

我宁愿查看可读的代码,也不愿查看性能提高 5% 但需要我一整天才能弄清楚它在做什么的代码。

最简单的

方法是强制转换,如果您确定 for 循环中的对象是Derived

void foo(float);
Base* pObject;
//...
//If you know with certainty that the object is a Derived
Derived& der = *static_cast<Derived*>(object)
for(float x : floatContainer)
{
     foo(der.function(x));
}

这意味着您只会调用 Derived 的 vtable,这可能会更快,具体取决于从 Derived 派生的类数量。如果你只能保证这个类是一个Base,那么你在上面的问题中写的本质上是一个vtable,除了比编译器产生的任何东西慢得多。您可能听说过 vtables 很慢,与原始 C 指针和函数相比,也许这是真的,但我几乎可以完全保证它足够快以满足您的需求。