30

在 C++ 中,可以获取指向类的(非静态)成员函数的指针,然后在对象上调用它。如果函数是虚拟的,调用将根据对象的动态类型动态调度。通过显式提供包含要使用的版本的范围,也可以(不使用成员指针)单态地调用对象的虚拟成员函数。下面的代码演示了这一点:

#include <iostream>
using std::cout; using std::endl;

struct Foo
{
    virtual void foo() { cout << 1 << endl; }
};

struct Foo2: public Foo
{
    virtual void foo() { cout << 2 << endl; }
};

int main( int, char** )
{
    Foo *foo = new Foo2;

    void (Foo::*foo_pointer)() = &Foo::foo;

    foo->foo();            // prints 2
    foo->Foo::foo();       // prints 1
    (foo->*foo_pointer)(); // prints 2
}

我想做的是将两者结合起来,并获得一个指向成员函数的单态版本的指针;即,我想要一个指向 Foo::foo 的指针,它总是调用 foo 的基类版本,并打印 1,即使它是在 Foo2 上调用的。但是,我还没有找到一种方法来做到这一点。可能吗?

(除了繁琐的手动编写一个新的非虚拟函数来进行单态调用,然后得到一个指向它的指针。)

4

3 回答 3

12

这在GCC中是可能的,但它在 C++ 语言扩展部分中记录的方式表明没有可移植的方式来做到这一点。

你可以做两件事:

  1. 如果您控制该类,请为其创建一个非虚拟函数和一个虚拟包装器,当您知道不需要虚拟调度时,只需获取非虚拟函数的地址即可。
  2. 如果不这样做,请创建一个模板仿函数,它将保存成员指针并进行显式范围调用。
于 2011-02-21T15:46:15.247 回答
0

换句话说:你想作弊。

不,这是不可能的,因为这就是多态性与指向成员方法的指针相结合的工作方式。

于 2011-02-21T10:27:53.617 回答
0

详细说明包装函数的代码示例(尽管 OP 想要避免这种方法!),因为在许多情况下,这是务实的优选解决方案:

#include <iostream>
using std::cout; using std::endl;

struct Foo
{
    virtual void foo() { cout << 1 << endl; }
};

struct Foo2: public Foo
{
    virtual void foo() { cout << 2 << endl; }
};

void monomorphicFooFoo( Foo * f ) { f->Foo::foo(); }

int main()
{
    Foo *foo = new Foo2;

    void (*baseFoo)( Foo * ) = &monomorphicFooFoo;
    baseFoo( foo ); // Prints 1
}
于 2015-04-21T08:41:19.203 回答