获取指向虚方法的指针?

时间:2012-06-26 19:53:44

标签: c++

我有一个需要在循环中多次调用虚方法的函数,并且希望每次都能有一种方法来避免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进行编译并进行全面优化。

4 个答案:

答案 0 :(得分:4)

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

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

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

答案 1 :(得分:2)

不要这样做。处理器有深层管道,编译器几乎肯定已经缓存了函数指针。你可以付出一些努力来做到这一点。但我保证,对于任何不到10年的编译器,这都没有区别。

答案 2 :(得分:0)

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

我宁愿看一下代码,这些代码比性能提升5%的代码更具可读性,但是我花了一整天的时间来弄清楚它在做什么。

答案 3 :(得分:0)

如果您确定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,除了比编译器产生的任何东西慢得多。您可能听说vtable很慢,也许与原始C指针和函数相比,这是真的,但我可以完全保证它足够快以满足您的需求。